Using functional components as an example, organize the TS notation used in the project. Keep replenishing…

1, the React. FC

FC before @ types/react18 provides children with implicit type (ReactElement | null), even if your Props note there is no definition of the children, you can still be deconstructed in the parameters of it. If type incompatibilities occur, you can display the declaration children? : React.ReactNode

To use props within a function, it must be defined explicitly. With this, the PropsType declaration is not needed.

interface BaseButtonProps{ disabled? : boolean; size? : ButtonSize; }export const Button: React.FC<ButtonProps> = (props) = > {
  const {
    disabled,
    size,
    children,
  } = props
  ...
}
Copy the code

The props annotation is not marked readOnly. Because ReadOnly is automatically added when you add it to a generic component

2, useState

Automatically derive, or pass in generics

 // Automatically deduce that user is of type string
const [user]=React.useState('a')

// Pass in generics
interface DataSourceObject{
  value: string;
}
type DataSourceType<T = {}> =  T & DataSourceObject
const [suggestions, setSuggestions] = useState<DataSourceType[]>([])
Copy the code

When the initial state is NULL, the declaration type needs to be displayed


type User = {name:string} 
1 / / examples
const [user, setUser] = React.useState<User | null> (null)
2 / / examples
const [user,setUser] = React.useState<User>({} as User)
Copy the code

3, useRef

// Use specific types if possible
// Using HTMLDivElement is much better than HTMLElement, much better than Element

function Foo(){ 
  const divRef = React.useRef<HTMLDivElement|null> (null); 
  return< div ref = {divRef} > etc < div / >} / / store the button dom const buttonRef = React. UseRef < HTMLButtonElement | null > (null); / / store a dom const linkRef = React. UseRef < HTMLLinkElement | null > (null);Copy the code

4、useImperativeHandle, forwardRef

export interface MyInputHandles {
    focus:() = > void;
}

const MyInput: RefForwardingComponent<MyInputHandles, MyInputProps> = (props, ref) = > {
    const inputRef = useRef<HTMLInputElement>(null);
    useImperativeHandle(ref, () = >({
        focus: () = > {
            if(inputRef.current) { inputRef.current.focus(); }}}))return <Input {. props} ref={inputRef}>    
}

export default forwardRef(MyInput)
Copy the code

5, useContext

These three are often used together to transfer data across components, as shown in the TS version below:

UseContext receives a context object (the return value of react. createContext) and returns the current value of the context. The current context value is determined by the value prop closest to the current component in the upper component. The syntax looks like this: const value = useContext(MyContext);

import React, {useContext} from "react"; type SelectCallback= (selectIndex: string) => void interface IMenuContext{ index: string; onSelect? : SelectCallback; defaultOpenSubMenus? : string[]; } export const MenuContext = createContext<IMenuContext>({ index: '0' }) const Demo3Child: React.FC<IProps> = () => { ... const context = useContext(MenuContext); return ( <div> {context} </div> ); } const Demo3: React.FC<IDemoProps> = () => { const passedContext: IMenuContext = { index: currentActive ? currentActive : '0', onSelect: handleClick, defaultOpenSubMenus, } return ( <MyContext.Provider value={passedContext}> <Demo3Child /> </MyContext.Provider> ); };Copy the code

6. UseCallback and useMemo

Both useMemo and useCallback receive the same parameters. They are executed after their dependencies change and return cached values. The difference is that useMemo returns the result of a function run, while useCallback returns a function. Generics can be passed in or auto-inferred. UseMemo’s generics specify the return value type and useCallback’s generics specify the parameter type

useCallback

function useCallback<T extends (… args: any[]) => any>(callback: T, deps: DependencyList): T;

// Automatic inference (value: number) => number
const multiply = React.useCallback((value: number) = > value * multiplier, [
  multiplier,
])

/ / generics
const handleChange = React.useCallback<
  React.ChangeEventHandler<HTMLInputElement>
>(evt= > {
  console.log(evt.target.value)
}, [])
Copy the code

useMemo

function useMemo(factory: () => T, deps: DependencyList | undefined): T;

interface IClass{
  classId: number,
  className: string,
  type: number,
  isGradeLeader:number
}
...
const [classInfo, setClassInfo] = useState<IClass[]>([])
const adminiClasses: IClass[] = useMemo(() = > classInfo.filter(item= > item.type === 1), [classInfo])
const teachingClasses: IClass[] = useMemo(() = > classInfo.filter(item= > item.type === 2), [classInfo])
// Automatically infer useMemo generics 
      []>
Copy the code

7. Event handlers

7.1. No Event parameter

const Test: React.FC = () = > {
    const handleClick = () = > {
        // Do a bunch of processing
    };
    return (
        <div>
            <button onClick={handleClick}>button</button>
        </div>
    );
};
Copy the code

7.2. Event Parameter

Do not do processing, directly write iron report error

const Test: React.FC<{}> = () = > {
    const handleClick: React.MouseEvent<HTMLButtonElement> = event= > {
        // Do a bunch of processing
        event.preventDefault();
    };
    return (
        <div>
            <button onClick={handleClick}>button</button>
        </div>
    );
};
OnClick is of MouseEventHandler typeonClick? : MouseEventHandler<T> |undefined;

// MouseEventHandler
      
        is a type alias. The generic type is Element
      
type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>;

// The generic Element is an interface from which many other interfaces are implemented
interface Element { }
interface HTMLElement extends Element { }
interface HTMLButtonElement extends HTMLElement { }
interface HTMLInputElement extends HTMLElement { }
// We recommend passing in a more specific Element interface,
Copy the code

The same goes for other events

7.3 List of event Types

  • AnimationEvent: CSS AnimationEvent
  • ChangeEvent:<input>.<select>and<textarea>Element change event
  • ClipboardEvent: Copy, paste, cut events
  • CompositionEvent: An event that occurs as a result of indirect text input by the user (for example, depending on browser and PC Settings, a pop-up window with extra characters may appear if you want to type Japanese on a US keyboard)
  • DragEvent: Drag-and-drop and interacted events on the device
  • FocusEvent: : The event in which the element gets focus
  • FormEvent: An event that occurs when the focus /value of a form element changes/the form is submitted
  • InvalidEvent: Fired when input validity limits fail (for example<input type="number" max="10">, insert the number 20)
  • KeyboardEvent: keyboard typing event
  • MouseEvent: indicates the event that the mouse moves
  • PointerEvent: Events generated by mouse, pen/stylus, or touch screen interaction
  • TouchEvent: An event that occurs when a user interacts with a touch device
  • TransitionEvent: CSS Transition, which is not well supported by browsers
  • UIEvent: The base event for mouse, touch, and pointer events.
  • WheelEvent: Scroll on a mouse wheel or similar input device
  • SyntheticEvent: The base event for all of the above events. Whether it should be used when the event type is uncertain

Since InputEvent is supported differently in different browsers, you can use KeyboardEvent instead

8. Ordinary functions

Ordinary functions are universal

  • An input/output function of a specific type;
// The input parameter is number
function testFun1 (count: number) {
    return count * 2;
}
Copy the code
  • An input and output function of uncertain type, but the input and output functions are of the same type;
/ / use generics
function testFun2<T> (arg: T) :T {
    return arg;
}
Copy the code
  • Async, which returns a Promise object, can be used to add a callback using the then method. Promise is a generic function. The T generic variable is used to determine the type of argument to the first callback received by the then method.
/ / interface
interface IResponse<T> {
    result: T,
    status: string
};

In addition to using interfaces, you can also use objects
// type IResponse<T> = {
// result: T,
// status: string
// };

async function testFun3() :Promise<IResponse<number>> {
    return {
        status: 'success'.result: 10
    }
}
testFun3.then(res= >{console.log(res)})
Copy the code

9. TS built-in types

  • Partial: Makes all properties in an object optional
interface IUser { name: string age: number department: string} Type optional = Partial<IUser>// The optional result is as followstype optional = { name? : string |undefined; age? : number |undefined; department? : string |undefined;
}
Copy the code
  • Omit: Generates a new type that has all attributes of T except the K attribute
type Foo = { name: string age: number } 
type Bar = Omit<Foo, 'age'> 
Type Bar = {name: string}
Copy the code
  • ConstructorParameters: a tuple of class constructor parameter types
  • Exclude: Exclude a type from another type
  • Extract: Selects a subtype that can be assigned to another type
  • InstanceType: InstanceType obtained from a new class constructor
  • NonNullable: Exclude null and undefined from a type
  • Parameters: a tuple of parameter types for a function
  • Readonly: Sets all properties of an object to read-only
  • ReadonlyArray: creates an immutable array of the given type
  • Pick: A subtype of an object type that contains a subset of its keys
  • Record: Mapping from key type to value type
  • Required: Make all attributes in the object Required
  • ReturnType: the ReturnType of the function

Here is a blog for more details: Several common types of built-in tools in TS

10. Custom hook

The custom of the Hook if the return value is an array type, TS is derived for the Union type automatically, solution: const assertion

function useLoading() {
    const [isLoading, setState] = React.useState(false)
    const load = (aPromise: Promise<any>) = > {
        setState(true)
        return aPromise.then(() = > setState(false))}return [isLoading, load] as const // This hook returns isLoading and a function
    // Actual: [Boolean, typeof load] type
    / / instead of automatic deduction: (Boolean | typeof load) []
}

// You can define a method that handles the tuple return value uniformly
function tuplify<T extends any[] > (. elements: T) {
  returnElements} use the above examplereturn [isLoading, load] as constInstead of = >return tuplify(isLoading, load)
Copy the code

11, React.Com ponentProps

To get the props typeof the component, use React.ComponentProps

For example, the child component must take a name argument, and the parent component needs to pass its props to the child component. The parent component needs to take the necessary type of the child component to define its Iprops. Use react.componentprops to get the necessary types for the subcomponents, and define your own Iprops with the cross type &.

Reduce unnecessary exports of Type by looking up types, and if you need to provide complex types, extract them into files exported as public apis.

// counter.tsx
import * as React from 'react'
export type Props = {
  name: string
}
const Counter: React.FC<Props> = props= > {
  return <></>
}
export default Counter

//app.tsx
import Counter from './d-tips1'
type PropsNew = React.ComponentProps<typeof Counter> & {
  age: number// This is what the app component wants
}
const App: React.FC<PropsNew> = props= > {
  return <Counter {. props} / >
}
Copy the code

12. Specific types of React. Children

React.Children provides a practical method for dealing with opaque data structures for this.props. Children. Some special processing is required when used with components that specify in the parent component that their children can only be features. For example, the Menu component can contain only MenuItem or SubMenu, not other elements

//Menu.tsx
import { MenuItemProps } from './menuItem'
const renderChildren = () = > {
    return React.Children.map(children, (child, index) = > {
     // Restrict Menu to MenuItem or SubMenu, not other elements
      const childElement = child as React.FunctionComponentElement<MenuItemProps>
      const { displayName } = childElement.type
      if (displayName === 'MenuItem' || displayName === 'SubMenu') {
        return React.cloneElement(childElement, { index: index.toString() }) 
        // Mix index into the instance
      } else {
        console.error('Warning:Menu has a child which is not a MenuItem or SubMenu component')}})}...//menuItem.tsx
exportinterface MenuItemProps{ disabled? : boolean; index? : string; className? : string; style? : React.CSSProperties; }const MenuItem:React.FC<MenuItemProps>=(props) = >{
    return (
     <li>{children}</li>
    )
}
MenuItem.displayName='MenuItem'
export defult MenuItem
Copy the code