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
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.
So you need to define a string that contains both red and blue, as well as other than red and blue
I typed white, and no error was reported
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.
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~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。