枚举类型怎么定义?

有这么一个常量FieldTypes,代表表单项类型,是输入框还是开关还是其余等等,只列举两个

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

此时子组件须要接管一个typeprops,类型的值为FieldTypes中的定义的值,即'input' | 'switch'等等

解法一:

typescript中enum能够作为类型束缚某个变量,如果这么做,那么给这个propstype赋值时,必须从enum中去取,保障了数据的起源以及数据类型的统一性,毛病是在某些场景下不是特地灵便

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

解法二:

应用只读的 object 来代替enum的作用

const FieldTypesObj = {  INPUT: 'input',  SWITCH: 'switch'} as const // <-- 要害技巧 1: as consttype Type = typeof FieldTypesObj // <-- 要害技巧 2: 用 typeof 关键字从 FieldTypesObj 反向创立同名类型const _type1: Type[keyof Type] = 'input' // ✅ correctconst _type2: Type[keyof Type] = FieldTypes.SWITCH // ✅ correct

常量断言(语法写作 as const)是 TypeScript 3.4公布的新个性,这里对它进行简略的解释:

先看上面例子:

let str = 'ghostwang' // str: stringconst 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]

看出区别来了么,应用as const会通知编译器为表达式推断出它能推断出的最窄或最特定的类型。如果不应用它,编译器将应用其默认类型推断行为,这可能会导致更宽泛或更个别的类型,并且此时他的属性是只读的(当然还是有方法能批改)

事件类型该怎么定义?

置信有人在定义事件的时候有时候不晓得怎么去定义,例如上面的场景,div点击时阻止冒泡

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

这里很多会定义为e:any 而后冒泡的函数是啥,阻止冒泡stop什么什么,再去查一下。

其实想一想,如果能晓得<div>的props的类型定义,我能够间接定义onClick这个函数,从而e就有类型了,不仅能够查看代码,还能够失去敌对的提醒。JSX提供了这样一个查问组件props的泛型:

// 取得div标签的props的类型 (内置组件,例如 div、a、p、input等等)const DivPropsType = JSX.IntrinsicElements<'div'>// 取得自定义组件的propsconst CustomPropsType = JSXElementConstructor<CustomComponent>

为了缩小记忆的累赘,React对这2个泛型又进行了一步包装:

type ComponentProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =        T extends JSXElementConstructor<infer P>            ? P            : T extends keyof JSX.IntrinsicElements                ? JSX.IntrinsicElements[T]                : {};

所以下面的事件类型定义就变得非常简单了:

import { ComponentProps } from 'react'const onClick: ComponentProps<'div'>['onClick'] = (e)=>{// e的类型被主动推导    e.//会失去代码提醒}<div onClick={onClick}><div>

同样,咱们在引入自定义组件时,也不须要独自引入它的props类型,间接应用这个泛型即可:

import { type ComponentProps } from 'react'const onClick: ComponentProps<typeof Custom>['onClick'] = (e)=>{// e的类型被主动推导    e.//会失去代码提醒}<Custom onClick={onClick}></Custom>

怎么定义一个字符串类型,既有枚举,又能够自在输出?

这种利用场景十分常见,我这样写题目,可能表白得不清晰,举一个例子:

我须要定义一个color类型,在开发者输出时,能够提醒输出 "red" 和 "blue",然而除了red和blue也能够自在输出其余字符串

然而这样定义类型的话,除了red和blue,其余都输出不了。都会报错。

如果加上string,间接什么都不提醒了

所以须要定义一个既蕴含red和blue,又蕴含除了red和blue之外的字符串

我输出了white,也不会报错

ref的类型该怎么定义?

ref的利用场景罕用来贮存一些扭转不会引起从新渲染、用来援用forwardRef的组件、援用内置组件应用。

import { useRef } form 'react'const valueRef = useRef<number>(0)

这种形式定义的valueRef的类型是MutableRefObject 可变的援用对象

除了这种形式,还有一种不可变的,对应的类型是RefObject 只读的援用对象 感觉这俩就是const和let一样

看一下区别

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" ,因为它是只读属性。

所以咱们在定义几种场景时,应辨别是手动赋值还是主动赋值,并应用不同的类型

例如用来封装一个useUUID的hook

import { useRef, type RefObject } form 'react'// 定义只读的refexport const useUUID = ()=>{    const uuidRef: RefObject<string> = useRef('uuid' + Date.now().toString(16));        return uuidRef.current}

例如援用一个div的ref

import { useRef, type RefObject } form 'react'const divRef: RefObject<HTMLDivElement> = useRef();<div ref={divRef}></div>

forwardRef的类型该怎么定义以及援用时类型该怎么定义?

依据官网的举荐,在定义forwardRef时,将类型定义在高阶函数中(留神⚠️props的类型和ref类型地位相同)

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

在引入时,typeof ComA 失去的是一个ref和props的穿插类型,所以只需拜访出ref的类型即可

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

React在此处设计的类型是ComponentProps<typeof ComA>['ref'] 返回的是一个React.Ref泛型

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

正好兼容了ref的3种状况,应用函数接管(createRef),useRef援用,和初始空值。而且还是个只读的ref

而后拜访tRef时,此时tRef即是曾经收窄的类型,具备敌对的提醒和取值限度。

写在最初的话

至此,联合最近组内小伙伴分享的一些ts类型应用技巧,在此总结并分享给更多的人,感激浏览~