typescript

grammar

1.aTag add clSTAG custom tag type error

  • reference

Add DECLARE namespace JSX and Declare Module ‘React’

Does not work and introduces a new TS check error

  • reference

According to the HTML5 standard, any custom tag should use a definition starting with data-

  • The final solution will be
<a clstag={`.... `}>{children}</a>Copy the code

Change to the following format, barely cheat the check, to the point of no error. Instead, look for ways to extend the HTMLAnchorElement property

const props = { clstag: '... ' } <a {... props}>{children}</a>Copy the code

2, about themobx-reactthe@injectProperties have been injected, but type validation is still indicating a missing property when using this component

  • See the way to avoid directly accessing props through a custom get injected property, which requires writing one more method in each component

  • Adopt the scenario, used after injecting properties! Indicates that the attribute is confirmed to exist.

    const { router } = this.props.store!
    Copy the code

3. Add attributes to objects at run time by extension&

For example, storeProp is used in store/header

export interface IHeader {
  logoPlayed: boolean
  setLogoPlayed: (v: any) = > void
  restoreLogoPlayed: (a)= > void
}

@storeProp({
  setter: [{default:!!!!! storage.get('logoPlayed'),
      name: 'logoPlayed',}]})class Header {
  public headerProp = false
}

const header = new Header() as IHeader & Header

export { Header }

export default header
Copy the code

When you use the header, you get the IHeader and all the attributes in the header

4. Require that each instance’s properties have initial values, which can be set either in constructor or at declaration time

Property 'fetchBatch' has no initializer and is not definitely assigned in the constructor.
Copy the code

If a method in a normal class is defined without any implementation, the above error will be reported. One solution is to write:

public restoreBatch! :(a)= > void
Copy the code

It’s a bit of a hassle to write this every time, so you can add the following configuration to tsconfig.json:

"strictPropertyInitialization": false,

Copy the code

More seriously, however, any methods that are not implemented should not be written in ordinary classes, but in abstract ones. Therefore, when the above situation occurs, the code should be implemented as follows:

abstract class A{
  public restoreBatch: (a)= > void
}

class B extends A{}
const b = new B()
export default b
Copy the code

5. Exported variables cannot be used as types, even if the variable is assigned from a class

class A {}
export const A1 = A

// other file
import { A1 } from 'A'
// A1 is only used as a variable, not as a type.
// a pit 🥵!
Copy the code

6, high order componentschildrenThe type definition

For example, the children type of the SRC/Component /Permission component should be defined as children: react.reactNode. React defines the ReactNode type as:

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
Copy the code

7, antdForm.create()decorator

This modifier is currently unavailable in TS and can only be replaced with function

Such as:

@Form.create()
class Test{}
Copy the code

Replaced by:

class Test{}

Form.create()(Test)
Copy the code

The official explanation

8. There are two ways to solve the following exceptions

Exception information:

Property 'store' is missing in type '{}' but required in type 'Readonly<RcBaseFormProps & Pick<IProps, "store">>'.
Copy the code

Search. TSX source code:

interface IProps {
  store: {
    rollbackEdit: RollbackEditStore
  }
  form: WrappedFormUtils
}

@inject('store')
@observer
class Search extends React.Component<IProps> {
  public store: RollbackEditStore
  constructor(props: IProps) {
    super(props)
    const {
      store: { rollbackEdit },
    } = this.props
    this.store = rollbackEdit
  }

  public onChange = (value: SelectValue) = > {
    const { form } = this.props
    this.store.setType(value)
    this.store.setList([])
    form.setFieldsValue({
      id: undefined, }) } public render() { ... }}export default Form.create()(Search)

Copy the code

The first solution:

Remove the constructor definition of a store reference. Add an optional question mark after the store of IProps

interface IProps { store? : {rollbackEdit: RollbackEditStore
  }
  form: WrappedFormUtils
}
Copy the code

Const {rollbackEdit} = this.props. Store!

The second solution:

TSX, simply pass store to it in the index. TSX call:

const store = {
  rollbackEdit,
}

const RollbackEdit = (a)= > (
  <Card
    title={
      <CardTitle>
        <Search store={store} />
      </CardTitle>
    }
    bordered={false}
  >
    <List />
  </Card>
)

Copy the code

9. Typescript causes Webpack split chunk invalidation.

reference

With ts official website, etc., that tsconfig

module: 'commonjs'
Copy the code

Must result in code splitting effectiveness and must be configured to

module: 'esnext'
Copy the code

The commonJS package is used in webpack.config.ts, which is clearly stated in the TS documentation

export = xxxx
Copy the code

The exported package must be used

import xxx = require('xxx')
Copy the code

In the way of introduction. But as long as this package is used, esNext’s module type is not available.

Options:

  1. usetsconfig-paths-webpack-pluginAnd introduce another onetsconfig.jsonFile that the file usesesnextModule mode.
  2. The more concise way is inwebpackthets-loaderaddoptionsTo enable the front-end compilation environment to use a different TSConfig configuration than the source environment.
options: {
  compilerOptions: {
    module: 'esnext',}},Copy the code

Double variability of function types

For details, see: double variability of function types

Type guard and type distinction

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function getSmallPet() :Fish | Bird {
    // ...
}

let pet = getSmallPet();

// Every member accesses an error
if (pet.swim) {
    pet.swim();
}
else if (pet.fly) {
    pet.fly();
}
Copy the code

To make this code work, we need to use type assertions:

let pet = getSmallPet();

if ((<Fish>pet).swim) {
    (<Fish>pet).swim();
}
else {
    (<Bird>pet).fly();
}
Copy the code

Notice here that we have to use type assertions multiple times. It would be nice if once we checked the type, we could clearly know the type of PET in each subsequent branch. TypeScript’s type-guarding makes this a reality. Type guards are expressions that are checked at run time to make sure the type is in a scope. To define a type guard, we simply define a function whose return value is a type predicate:

function isFish(pet: Fish | Bird) :pet is Fish {
    return (<Fish>pet).swim ! == undefined; }Copy the code

In this case, pet is Fish is the type predicate. The predicate is of the form parameterName is Type. ParameterName must be a parameterName from the current function signature. Whenever isFish is called with some variable, TypeScript reduces the variable to that specific type, as long as the type is compatible with the variable’s original type.

// The 'swim' and 'fly' calls are ok now

if (isFish(pet)) {
    pet.swim();
}
else {
    pet.fly();
}
Copy the code

Check the type of CSS-Module

We took a deroute at first, using typescript-plugin-CSS-modules, which doesn’t support less well, breaks when using complex LESS functions, and often needs to restart tsServer when updating LESS files. Typings -for- CSS -modules-loader

Use a Webpack loader to instantly generate the corresponding.d.ts file to map CSS Modules’ classes.

TSC command line parameters

When only one file is compiled, tsconfig.json for the current project is not automatically loaded if the TSC parameter is specified. This is confusing and will generate incorrect compilation results.

14,ts-loaderwithfork-ts-checker-webpack-pluginwithawesome-typescript-loader.

Ts-loader is used independently, without command line type verification prompt, and the more items, the slower the compilation. Ts-loader needs to be used together with fork-ts-checker-webpack-plugin. It can compile files in seconds after update and display type verification on the command line, but consumes a lot of memory. Awesome-typescript-loader consumes less memory, compiles faster when files are updated, and displays command-line type validation. For example, if you are changing files that depend on more, such as the lower-level store that the View depends on, the compilation will be slightly slower.

15,typescriptwithpreactwithweb component.

You first need to add it in tsconfig.json

  "jsx": "react"."jsxFactory": "h".Copy the code

When using the custom DOM in preact, you need to extend IntrinsicElements, which can be found in Google to extend JSX under Global

declare namespace JSX {
    interface IntrinsicElements {
        foo: any}}Copy the code

However, JSX resides in a different namespace in a Preact environment

declare global {
  namespace preact {
    namespace h {
      namespace JSX {
        interface IntrinsicElements {
          'custom-node': any
        }
      }
    }
  }
}

Copy the code

configuration

16,tsconfig.jsonPath alias ofpath

If it’s for your current project, feel free to use it

When used with other projects, in my case as a multi-package LerNA project, one package needs to import another package’s TS file, so the path alias in the original package does not work in the other package.

17,.d.tsWith the release

When the project is published, even if declaration in tsconfig.json is opened, the.d.ts files in it will not be automatically compiled to the directory specified by outDir

If there are definitions in the project that rely on these.d.ts, additional replication scripts need to be added during the release process

Try not to use import to introduce other dependencies in.d.ts. In particular, do not introduce the type of impure definition file, such as the actual logical code in the file, otherwise it will not work in the environment using the package after distribution

18. Compile with Babel

Because there are many abstract classes defined using Abstract in the project, the abstract classes are used only for type checking at TS-Loader compilation time. However, when compiled with Babel, the abstract class generates the real class, and its properties are generated along with the class. A collision caused by using mobx extended attributes will not run.