Why use TypeScript?
The pain point of weakly-typed JavaScript in everyday development
- The referenced component/function does not know the accepted parameters and their types —– various documentation —- even deep into the source code
- Data flow of complex data is difficult to track —- various Debugger or log checks
- BFF/ backend interface fields and field types are unclear —- various search documents —- responsible person
- The interface type that the bottom layer depends on changes —- The global search of the front end replaces changes —- debugging
TypeScript was born for type definition and has the following advantages
- Define the properties of the component and the parameters of the function, and the code is the document showing the corresponding types
- Define the type of complex data, and the data type can be clearly known when the data flow, so as to facilitate tracking
- For the back-end interface, the specification defines the type, which is easier to maintain
- Static type checking to find problems at the coding stage
- Powerful IDE auto-complete/check
Benefits and costs
- Benefits: early exposure of problems, tracking of complex data flows, intelligent hints from IDE, powerful Type system
- Cost related: Increased learning and type maintenance costs
TypeScript in React
Development environment: ESLint+Prettier+TypeScript Playground with React
ESLint
- ESLint –Javascript Lint, which regulates code quality and provides development efficiency
- Install dependencies
- Eslint: Javascript code detection tool
- @typescript-eslint/eslint-plugin: List of TS rules. You can turn each rule on or off
- @typescript-eslint/parser: Converts TS to ESTree so it can be detected by ESLint
- Configuration. The eslintrc
- Parser: Specifies the Parser that ESLint uses: Esprima, babel-eslint, @typescript-esLint/Parser Default Esprima
- parserOptions: {
EcmaVersion: 6 // ES version
SourceType: ‘module’, // set to “script” (default) or “module” (ES6).
EcmaFeatures: {// This is an object that represents additional language features you want to use: JSX: true // enable JSX}
},
- Extends: Extends an inherited rule that can be overridden in rules
- Plugins: Use third-party Plugins
- Rules: (“off” or 0 – off rules; Warn “or 1 – opens the rule, using the warning program will not exit; Error “or 2 – enable the rule and exit using the error program)
Prettier
- Unified team coding style, ensure the readability of code, can set save automatic formatting
- Install dependencies
- Prettier: Formats code according to configuration
- Eslint-config-prettier: Disables any linting rule that would interfere with the existing Prettier rule
- Eslint-plugin-prettier: Runs prettier analysis as part of Eslint
-
Configuration. The eslintrc. Js
{
“singleQuote”: true,
“trailingComma”: “es5”,
“printWidth”: 80,
“semi”: true,
“tabWidth”: 4,
“useTabs”: false }
Tools :TypeScript Playground with React
You can debug React+TypeScript online. Note: You can debug only types, not code
VSCode editor
In the Workspace Settings, configure the check file scope to ensure that.ts and.tsx files in the React project have automatic repair.
{
"eslint.validate": ["typescript", "typescriptreact"]
}
Copy the code
Configuration tsconfig. Json
{"compilerOptions": {/* Basic options */ "target": "es5", // Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT' "module": "commonJS ", 'commonjs', 'AMD ', 'system', 'umd' or 'es2015' "lib": [], // Specify the library file "allowJs" to include in the build: True, // Allow javascript file "checkJs": true, // report error in javascript file "JSX ": "preserve", // specify JSX code generation: 'preserve', 'react-native', or 'react' "declaration": true, // generate the corresponding '.d.ts' file "sourceMap": True, / / generate the corresponding 'map' file "outFile" : ". / ", / / the output files into one file "outDir" : ". / ", / / specifies the output directory "rootDir" : "Outdir. removeComments": true, "noEmit": true ", "importHelpers": True, // Import the helper function "isolatedModules" from tslib: True, // treat each file as a separate module (similar to 'ts.transpilemodule'). /* Strict type checking options */ "strict": true, // Enable all strict type checking options "noImplicitAny": StrictNullChecks: true, // enable strictNullChecks on "noImplicitThis": True, // Generate an error "alwaysStrict" when this is of type any: // Check each module in strict mode and add 'use strict' /* Extra check */ "noUnusedLocals": true, // If there are any unused variables, throw the error "noUnusedParameters": True, / / a unused parameters, throw an error "noImplicitReturns" : true, / / not all there is in the function code when the return value, throw an error "noFallthroughCasesInSwitch" : True, // Switch statement fallthrough error reported. /* moduleResolution options */ "moduleResolution": "Node ", // Select the module resolution policy: 'node' (node.js) or 'classic' (TypeScript pre-1.6) "baseUrl": "./", // Base directory "paths" for resolving non-relative module names: {}, // list of module names to baseUrl pathmaps "rootDirs": [], // List of root folders whose combined contents represent the structural contents of the project runtime "typeRoots": [], // List of files containing type declarations "types": [], / / need to include the type of statement file name list "allowSyntheticDefaultImports" : true, / / allows never to set the default import export modules by default. /* Source Map Options */ "sourceRoot": ". ", // specifies where the debugger should find the TypeScript file instead of the Source file "mapRoot": "./", // specify the location where the debuggler should find the mapping file instead of generating the file "inlineSourceMap": true, // Generate a single Soucemaps file instead of generating a different sourcemaps file "inlineSources": True, // Generate the code to a file with sourcemaps, requiring either the --inlineSourceMap or --sourceMap attribute to be set at the same time /* other options */ "experimentalDecorators": True, // Enable decorator "emitDecoratorMetadata": true // provide decorator metadata support}}Copy the code
React Component Declaration
-
Class component, defined using react.component< P,S> and react.pureComponent <P,S,SS>
- P is Props, S is State, and SS is the value returned by Snapshot
- In addition to constraining the Props parameter, the class component also needs to define State. If optional parameters are available, you need to define default values. Use the static keyword in the class component.
- React is a one-way data stream, Props is not allowed to be modified in child components.
- Try it on TS Playground
-
The React FunctionComponent, which uses the React.FunctionComponent to define function components, can be used to define functions directly
- React.FC defines the type and return value of Children inside the react. FC definition
- Props needs to define the Children type themselves
- Try it on TS Playground
-
Stateless components: An SFC type is already defined in the React declaration file
// Interface IProps {onClick(event: MouseEvent)=> void} const Button: React.SFC = ({ onClick, children }) => { return
{children}}
-
JSX.Element vs ReactNode vs ReactElement
ReactElement is an object with type and attributes, obtained by executing React. CreateElement or by translating JSX
A ReactNode is a collection of various types. It is a ReactElement, ReactFragment, string, number or array of ReactNodes, or Null, undefined, or Bool
Class component type definition: Returns a ReactNode with Render (), which is looser than the actual value range of React
Function component type definition: returns jsX. Element, which is also looser than the actual value range of React
//React.ReactElement const ComA: React.ReactElement<myComponent> = <myComponent /> // Accept a component that can function at Props and render using JSX const ComB: React.Component< ComProps > = ComA; // Render ComB with some props: <ComB {... ComProps} />; // React.ReactNode: Render something like JSX or string interface Props = {header: react.reactnode; body: React.ReactNode; }; const MyComPonent2:React.FunctionComponent<Props> = (props)=>{ const { header, body, footer } = props return ( <> {header} {body} </> ) } <MyComponent2 header={<h1>Header</h1>} body={<i>body</i>} />Copy the code
- Try implementing a generic component in TS Playground
React Hook
-
UseState ts Playground
-
useEffect
//2. UseEffect: The function passed in by useEffect returns either a method (cleanup function) or undefined, otherwise an error will be reported. UseEffect (async () => {const user = await getUser() setUser(user)}, UseEffect (()=>{const getUser = async ()=>{const user = await getUser() setUser(user)} getUser()},[])
-
useRef
- When using useRef, there are generally two ways to create a Ref container with no initial values.
// option 1 const ref1 = useRef(null); // option 2 const ref2 = useRef(null!) ; // option 3 const ref3 = useRef
(null);
-
The difference between the two? RefObject VS MutableRefObject
-
Try it on TS Playground
-
forwardRef
- Because a function component has no instance, it cannot receive a REF attribute like a class component
- Try it on TS Playground
-
useImperativeHandle
- Customize the values exposed to the parent component
- Try it on TS Playground
-
useReducer
- Try it on TS Playground
-
Customize the Hook
- With custom hooks, component logic can be extracted and reused
- Avoid type inference when writing a custom Hook that returns an array
- We need to customize the return value or to return an array that asserts const
- Try it on TS Playground
The event processing
-
Event Indicates the type of the Event object
- All type definitions have the same format:
React. event name <ReactNode>
- Try it on TS Playground
// React.SyntheticEvent (@types/ React /index.d.ts) all events are its subtypes. Form event const onSumbit = (e: react.ChangeEvent)=>{… } //2. Input event const onChange = (e: react. ChangeEvent)=>{… } // other events // 1. ClipboardEvent<T = Element> ClipboardEvent object // 2. DragEvent<T = Element> DragEvent object // 3. MouseEvent<T = Element> MouseEvent object // 6. TouchEvent<T = Element> WheelEvent<T = Element> AnimationEvent<T = Element> AnimationEvent<T = Element> Transition event object
- All type definitions have the same format:
-
Event handler type
When we define event handlers, is there a more convenient way to define their function types? ——-EventHandler
EventHandler receives E, which represents the type of the Event object in the Event handler.
interface IProps {
onClick : MouseEventHandler<HTMLDivElement>,
onChange: ChangeEventHandler<HTMLDivElement>
}
Copy the code
Promise type
In the code, we will encounter Async function which returns a Promise object. How to define it?
Promise is a generic type. The T generic variable is used to determine the parameter type of the first callback function (onfulfilled) received when using the THEN method
interface IResponse<T> { message: string, result: T, success: boolean, } async function getResponse (): Promise<IResponse<number[]>> {return {message: 'get success ', result: [1, 2, 3], success: true, } } getResponse() .then(response => { console.log(response.result) })Copy the code
Practical skills
-
Interface or type
- Extensions: Interface is based on extends and type is based on the cross type &
- Type can declare basic type aliases, union types, tuples, etc., and get instance types with Typeof.
- Interface can declare merge
- You can implement priority interfaces with interfaces
-
Type extraction (Index Type, mapped Type, Keyof)
interface UserInfo{ id:number name:string status: 1|2|3|4 } // index type type UserStatus = { id: UserInfo[‘id’]
status:UserInfo[‘status’] } // mapped type type UserStatus = { [K in ‘id’|’status’]:Userinfo[K] } // keyof function getStatus<T extends { [key:string]:any },K extends keyof T>(obj:T,key:K):T[K]{ return obj[key] } const status = getStatus(UserInfo,’status’) -
Use Typeof to quickly define interface types
const INIT_OPTIONS = { id:101, name:’banggan’, age:26, tel:1809999999, }; interface Options { id: number name: String age :number tel:number} type Options = typeof INIT_OPTIONS // Typeof in Ts can be used to obtain a real variable, object type, or function type
-
Try it in the tool generic TS Playground
const info = { name:’banggan’, age:26, Sex :’man’ location:’ Beijing ‘tel:88888888} ‘woman’} const info1 = {sex: sex_map. man} —-keyof valueof // keyof returns a combined type of all keys in a type // ts does not have valueof keyword, SEX_MAP1 {man:0, woman:1} interface Info {name: string age: number sex: keyof SEX_MAP1 | SEX_MAP1[keyof SEX_MAP1] } const info2: Info = { name:’sb’, age:1, sex: ‘man’ } const oldInfo: Info={name:’1′, age: 1, sex: 0} Record<T, U> T const s: Record<keyof Info,string> = { name:’123′, age:’111′, sex:’man’ }
Type MyRcord<T extends keyof any,U> = {[k in T]:U} Type MyRequired ={[P in keyof T]-? :T[P]} // All become readable type MyReadonly = {readonly [P in keyof T] :T[P]} // If only some attributes for required operations —-Pick // Pick from T Pick a few key inside, such as Pick < type1, ‘key1’ | ‘key2’ >. Make what you want, optional key choice for again cross types make up the rest of the type Info1 = Partial < Pick < Info, ‘name’ | ‘sex’ > > & {age: number} const info3: Info1 = {name:’1111′, age:1} // Omit an attribute. If Omit < type1, ‘key1’ | ‘key2’ >, said the selection in addition to other key key1 and key2 type1. Type Info2 = Partial < Pick < Info, ‘name’ | ‘sex’ > > & Omit the < Info, ‘name’ | ‘sex’ > / / Pick implementation – type in MyPick < T, K extends keyof T> = {[P in K]:T[P]} condition type type SuperPick<T,K extends keyof any> = {[P in K extends keyof T? K:never]:T[P]} condition type extends keyof T? K:never]:T[P]} A extends B type isNumber = T extends Number? T:never type test1 = [isNumber<1>,isNumber,isNumber<‘1’>] Exclude<T,U> = T extends U? Never :T type MyOmit<T,K extends keyof any> = Pick<T,MyExclude<keyof T,K>> // infer —- Infer is the type variable MyReturnType = T extends (… args:any[])=> infer P ? P:any // Promise can be used for items of array type
// Two key combinations of an object — joint type solution Don’t really know the return value / / assert that the function is type isDiv Element (ele: | null) : ele is HTMLDivElement {return ele && ele. NodeName = = = “DIV”} function isCanvas(ele:Element |null):ele is HTMLCanvasElement{ return ele && ele.nodeName === “CANVAS” } function commonQuery(selector:string){ const ele = document.querySelector(selector) if(isDiv(ele)){ console.log(ele.innerHTML) }else if (isCanvas(ele)){console.log(ele. GetContext)}} // Window window attributes interface window {a:number}
Author: Xiao Fang