preface

Typescript provides type validation and code hints, and it’s important to include Typescript in large projects

The React project introduces Typescript from 0 to 1, as well as possible problems and solutions

This article will continue to update, code word is not easy, thumbs up support!!

A, install,

npm i typescript @types/react @types/react-dom @types/node @types/jest
Copy the code

Second, the configuration

Create tsconfig.json in the project root directory

{"compilerOptions": {"target": "es5", // target version "lib": ["dom", "dom. Iterable ", "esNext ", "ScriptHost"], // Es5, ES6, ES7, DOM etc. ["dom", "es5", "scripthost"] // Target = es6: ["dom", "es5", "scripthost"] ["dom", "es6", "dom.iterable", "scripthost"] "allowJs": True, // Allows the compiler to compile JS, JSX files "checkJs":true, // Checks JS files "skipLibCheck": true, "esModuleInterop": True, / / allow the export = derived from the import from import "allowSyntheticDefaultImports" : True, / / allow the use of the import from XXX 'XXX' to introduce the module in the form of "strict" : true, / / open all strict type checking "forceConsistentCasingInFileNames" : True, "noFallthroughCasesInSwitch" : true, / / prevent switch statement through behind (that is, if there is no break statement won't execute) "the module" : ModuleResolution: "node", // moduleResolution: "node", // moduleResolution: "node", // "JSX ": "react-jsx"}, "include": ["src", "**/*.ts", "**/*.tsx"], "exclude": ["./node_modules"] }Copy the code

Check the JS file by setting “checkJs”:true. You can tell the compiler to ignore type checking for the current file by adding the // @ts-nocheck comment at the top of the.js file

Path mapping

Scenario: The introduction of a path alias with a red wavy line indicates that the module “@/XXX” or its corresponding type declaration cannot be found

Solution: Configure path to resolve non-relative paths

Create tsconfig.paths.json in the root directory

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "less/*": ["./src/assets/styles/less/*"],
    }
  }
}
Copy the code

In tsconfig.json

{"extends": "./tsconfig.paths.json", // same as compilerOptions" compilerOptions":{}}Copy the code

If you don’t want to split the configuration, configure tsconfig.json directly, and the final code looks like this

{"compilerOptions": {"target": "es5", // target version "lib": ["dom", "dom. Iterable ", "esNext ", "ScriptHost"], // Es5, ES6, ES7, DOM etc. ["dom", "es5", "scripthost"] // Target = es6: ["dom", "es5", "scripthost"] ["dom", "es6", "dom. Iterable ", "scripthost"] "allowJs": true, "SkipLibCheck ": true, "esModuleInterop": True, / / allow the export = derived from the import from import "allowSyntheticDefaultImports" : True, / / allow the use of the import from XXX 'XXX' to introduce the module in the form of "strict" : true, / / open all strict type checking "forceConsistentCasingInFileNames" : True, "noFallthroughCasesInSwitch" : true, / / prevent switch statement through behind (that is, if there is no break statement won't execute) "the module" : ModuleResolution: "node", // moduleResolution: "node", // moduleResolution: "node", // "JSX ": "react-jsx", "baseUrl": "."," Paths ": { "@/*": ["./src/*"], "less/*": ["./src/assets/styles/less/*"] } }, "include": ["src", "**/*.ts", "**/*.tsx"], "exclude": ["./node_modules"] }Copy the code

Restart the project for the configuration to take effect

Third party library

When referencing a third-party plugin in ts, check whether the third-party library has a type declaration file

Website: www.typescriptlang.org/dt/search?s…

Or if you mouse over it, you’ll be prompted to try installing a package before declaring a module

1. Libraries with declaration files

Example: the React-Helmet library

Search results:

To install

npm i @types/react-helmet --save-dev
Copy the code

2. Libraries without declaration files

If third-party JS files do not have Typescript type support, you need to use a declaration file

Example: the React – i18Next library

Create a new typings.d.ts file in the project SRC directory.

// Add declare Module "react-i18Next ";Copy the code

3. Register libraries or variables on Windows

Example: Libraries registered on Windows, such as Echarts, are introduced through the CDN

Modify the SRC/typings. Which s

// Add declare interface Window {echarts: any; }Copy the code

Importing non-JS modules using import will cause an error

Workaround: Add declarations to these non-JS modules

Modify the SRC/typings. Which s

CSS 'declare Module '*.less' declare Module '*.scss' // Image Declare Module '*.svg' DECLARE module '*.png'; declare module '*.jpg';Copy the code

6. Change the file to.tsx

First change the.jsx file to.tsx file, after the change, the project will compile error, then continue to solve the problem of error

1. Function components

React.FC adds children by default? : react. ReactNode property declaration

React.FC automatically verifies the fields in defaultProps

import {FC} from 'react' interface Props{ name? :string } const Greeting:FC<Props> =({name,children})=>{ return <div>Hello,{name},{children}</div> } Greeting.defaultProps = { name:2 }Copy the code

2. The type of component

<Props,State> specifies the inheritance and State types

interface Props { initialCount: number; } interface State { count: number; } class Counter extends React.Component<Props, State> { constructor(props: Props) { super(props); this.state = { count: props.initialCount, }; }}Copy the code

3. The module

If you have a large number of the same interface Props, you can extract them to an external module

New SRC/types/echartsCompoent. Ts

/ / data interface echarts ModelData {xAxis: string | number []; series: number[]; } export interface Props { theme: string; // Theme color model? : ModelData; }Copy the code

Use:

import React from 'react'
import { Props } from "@/types/echartsCompoent";

const Bar:React.FC<Props> = ({theme,model}) =>{return <></>}

export default React.memo(Bar)
Copy the code

4. Non-null assertion operators!

Tells the compiler that the object is of non-null and non-undefined type

Example: The target property of antD’s BackTop component tells the program that.current is non-empty through the non-empty assertion operator

const overFlowRef = useRef(null); <BackTop visibilityHeight={100} target={() => overFlowRef.current! } / >Copy the code

5. React.createContext

Here is an empty object whose data type is specified by type assertion

import { Dispatch } from 'react';

interface UserContextType {
  phone: string,
  setPhone: Dispatch<React.SetStateAction<string>>
}

const UserContext = React.createContext<UserContextType>({} as UserContextType)
Copy the code
// Subcomponent const Button = (props: props) => {const context = useContext(UserContext); Return (<button onClick={() => context.setphone ('234')}>{props. Name}-- {context.phone}</button>)} // Parent component const App = () => { const [phone, setPhone] = useState('123') return ( <UserContext.Provider value={{ phone, SetPhone}}> <Button name=" Button "/> </ userContext.provider >); }Copy the code

6. Type assertion

Scenario: When using antD’s Menu component, the business needs to determine the current theme color and then decide whether to highlight the current Menu bar

< menu. Item key="theme-black" className={theme === "theme-black" && "themeActive"} > Night mode </ menu. Item>Copy the code

But will quote: type can not be “false |” themeActive “” assigned to the type of” string | undefined “. You need to manually tell the program the type of the return value

< menu. Item key="theme-black" className={(theme === "theme-black" && "themeActive") as string} > Night mode </ menu. Item>Copy the code

7. useRef

Situation: An error is reported on ref

Solution: Give useRef an initial value of NULL

const wrapper = useRef(null);
Copy the code

8. useState

  1. Specify an initial value

Given an initial value, TS can perform type inference

const [currentPage, setCurrentPage] = useState(1);
Copy the code

Extension: If you set useState([]), ts deduces it to never[], so you need to specify the type of the initial value via generics

useState<any[]>([])
Copy the code
  1. No initial value is specified
interface User{
  userName:string,
  userId:number,
}

function UserInfo() {
  const [userInfo, setUserInfo] = useState<User | undefined>();
}
Copy the code
  1. Failure to specify an initial value

When defining a generic that contains undefined, the object value will encounter a “object may not be defined” validation error

Workaround: Use the optional chain operator?

interface User { userName: string; userId: number; } function UserInfo() { const [userInfo, setUserInfo] = useState<User | undefined>(); return ( <div> {userInfo? .userName} </div> ); }Copy the code

9. useSelector

const { fileName } = useSelector((state) => state.file);
Copy the code

Error: Property ‘XXX’ not found on type ‘DefaultRootState’

Solution:

Get all the data in redux using store.getState

The data typeof store is extrapolated through typeof

By ReturnType, we get the return value type of the function type

Example:

New SRC/store/store. Which s

import store from './index'

export type RootState = ReturnType<typeof store.getState>
Copy the code

use

import { RootState } from '@/store/store'

const { fileName } = useSelector((state:RootState) => state.file);
Copy the code

10. useReducer

interface IncrementAction { type: "INCREMENT"; } interface DecrementAction { type: "DECREMENT"; } / / type alias type CountAction = IncrementAction | DecrementAction; function countReducer(state: number, action: CountAction) { switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } } function Counter() { const [count, dispatch] = useReducer(countReducer,0); return ( <div> <button onClick={() => dispatch({type:'INCREMENT'})}>+</button> <div>{count}</div> <button onClick={() =>  dispatch({type:'DECREMENT'})}>-</button> </div> ); }Copy the code

11. require.context

When you get the contents of a file through webpack, there is no property “context” on the NodeRequire.

Solution: Install the WEBpack TS file

npm i @types/webpack-env -D
Copy the code

React element type

situation category
String, number React.ReactText
A single JSX element React.ReactElement
Multiple JSX elements React.ReactNode
portal React.ReactPortal

React Event types

situation category
React.MouseEvent Click on the event
React.keyboardEvent Keyboard events
React.DragEvent Drag and drop event
React.FocusEvent “Event”
React.ChangeEvent Form field value change event
React.FormEvent Form submission event
React.WheelEvent Mouse scroll event
React.TouchEvent Touch events

1. Click events

interface Props{ onClick? :(event:React.MouseEvent<HTMLButtonElement>)=>void }Copy the code

2. Form events

function App() {
  const [value1, setValue1] = useState('');

  const onChangeValue1 = (e:React.ChangeEvent<HTMLInputElement>)=>{
    setValue1(e.target.value)
  }

  return (
    <div>
      <input value={value1} onChange={onChangeValue1}/>
      <Button/>
    </div>
  );
}
Copy the code