2
头图

How are enumeration types defined?

There is such a constant FieldTypes , which represents the form item type, whether it is an input box or a switch or other, etc., just to list two

 enum FieldTypes {
  INPUT = 'input',
  SWITCH = 'switch'
  // ...
}

At this point, the subcomponent needs to receive a type of props , and the type value is the value defined in FieldTypes 5ee0221ea5d0ae61a58576fef06aff95---, that is, 'input' | 'switch'

Solution one:

typescrip t in enum can be used as a type constraint for a variable, if you do, then assign this props type Taking it from enum ensures the source of the data and the unity of the data type. The disadvantage is that it is not particularly flexible in some scenarios

 const _type: FieldTypes = FieldTypes.INPUT // ✅ correct
const _type: FieldTypes = 'input' // ❎ error

Solution two:

Use read-only object instead of enum

 const FieldTypesObj = {
  INPUT: 'input',
  SWITCH: 'switch'
} as const // <-- 关键技巧 1: as const

type Type = typeof FieldTypesObj // <-- 关键技巧 2: 用 typeof 关键字从 FieldTypesObj 反向创建同名类型

const _type1: Type[keyof Type] = 'input' // ✅ correct
const _type2: Type[keyof Type] = FieldTypes.SWITCH // ✅ correct

Constant assertion (syntax writing as const ) is a new feature released in TypeScript 3.4, here is a brief explanation of it:

Take a look at the following example:

 let str = 'ghostwang' // str: string
const str = 'ghostwang' // str: 'ghostwang'
let str = 'ghostwang' as const // str: 'ghostwang'

const obj1 = { name: 'ghostwang' } // const obj: { name: string; }
const obj2 = { name: 'ghostwang' } as const // const obj: { readonly name: "ghostwang"; }

const arr = [1, 2] // const arr: number[]
const arr2 = [1, 2] as const // const arr: readonly [1, 2]

Seeing the difference, using as const tells the compiler to infer for the expression the narrowest or most specific type it can infer. If you don't use it, the compiler will use its default type inference behavior, which may lead to a wider or more general type, and at this point his properties are read-only (of course there are ways to modify it)

How should event types be defined?

I believe that some people sometimes don't know how to define events when defining events, such as the following scenario, preventing bubbling when div is clicked

 const onClick = (e)=>{// 这里e的类型是什么?
    e...//
}

<div onClick={onClick}><div>

Many of them will be defined as e:any then what is the function of bubbling, stop bubbling and stop, and check again.

In fact, think about it, if I can know the type definition of props <div> , I can directly define the onClick function, so that e has a type, not only can I check the code, but also can get friendly prompts. JSX provides such a generic query component props:

 // 获得div标签的props的类型 (内置组件,例如 div、a、p、input等等)

const DivPropsType = JSX.IntrinsicElements<'div'>

// 获得自定义组件的props

const CustomPropsType = JSXElementConstructor<CustomComponent>

In order to reduce the burden of memory, React further wraps these two generics:

 type ComponentProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =

        T extends JSXElementConstructor<infer P>

            ? P

            : T extends keyof JSX.IntrinsicElements

                ? JSX.IntrinsicElements[T]

                : {};

So the above event type definition becomes very simple:

 import { ComponentProps } from 'react'

const onClick: ComponentProps<'div'>['onClick'] = (e)=>{// e的类型被自动推导

    e.//会得到代码提示

}

<div onClick={onClick}><div>

Similarly, when we introduce a custom component, we don't need to introduce its props type separately, just use this generic type directly:

 import { type ComponentProps } from 'react'

const onClick: ComponentProps<typeof Custom>['onClick'] = (e)=>{// e的类型被自动推导

    e.//会得到代码提示

}

<Custom onClick={onClick}></Custom>

How to define a string type, both enumeration and free input?

This application scenario is very common. I write the title like this, which may not be clear. Here is an example:

I need to define a color type, when the developer inputs, it can prompt to input "red" and "blue", but other strings can be freely input in addition to red and blue

img

But if you define the type like this, you can't input anything except red and blue. will report errors.

If you add a string, nothing will be prompted directly.

img

So you need to define a string that contains both red and blue, as well as other than red and blue

img

I typed white, and no error was reported

img

How to define the type of ref?

The application scenarios of ref are often used to store some changes that will not cause re-rendering, to refer to components of forwardRef, and to refer to built-in components.

 import { useRef } form 'react'



const valueRef = useRef<number>(0)

The type of valueRef defined in this way is MutableRefObject variable reference object

In addition to this method, there is also an immutable, the corresponding type is RefObject read-only reference objects feel that these two are the same as const and let

see the difference

 import { useRef, type MutableRefObject, type RefObject } form 'react'



const valueRef1: MutableRefObject<number> = useRef(0)

const valueRef2: RefObject<number> = useRef(0)



valueRef1.current = 1; // 正常

valueRef2.current = 1; // 报错,不能赋值: 无法分配到 "current" ,因为它是只读属性。

So when we define several scenarios, we should distinguish between manual assignment and automatic assignment, and use different types

For example, it is used to encapsulate a hook of useUUID

 import { useRef, type RefObject } form 'react'



// 定义只读的ref

export const useUUID = ()=>{

    const uuidRef: RefObject<string> = useRef('uuid' + Date.now().toString(16));

    

    return uuidRef.current

}

For example, a ref that refers to a div

 import { useRef, type RefObject } form 'react'



const divRef: RefObject<HTMLDivElement> = useRef();



<div ref={divRef}></div>

How to define the type of forwardRef and how to define the type of reference?

According to the official recommendation, when defining forwardRef, define the type in a higher-order function (note that the type of ⚠️props is opposite to the type of ref)

 const ComA = forwardRef<{dddd: string}, {age?: number}>((props, ref)=>{
  useImperativeHandle(ref, ()=>{
    return {
      dddd: "1"
    }
  })
  return <div></div>
})

At the time of introduction, typeof ComA gets a cross type of ref and props, so just access the type of ref

 const ComB = ()=>{
  const tRef: ComponentProps<typeof ComA>['ref'] = useRef();
  
  return <ComA ref={tRef}></ComA>
}

The type designed by React here is ComponentProps<typeof ComA>['ref'] returns a React.Ref generic

 type Ref<T> = RefCallback<T> | RefObject<T> | null;

It is exactly compatible with the three cases of ref, using function to receive (createRef), useRef reference, and initial null value. And it's a read-only ref 👍

Then when accessing tRef, tRef is the narrowed type, with friendly hints and value restrictions.

img

last words

So far, combined with some ts type usage skills shared by the friends in the group recently, I will summarize and share it with more people here. Thank you for reading~


MangoGoing
774 声望1.2k 粉丝

开源项目:详见个人详情