关于typescript:Typescript类型常用使用技巧1

35次阅读

共计 3746 个字符,预计需要花费 10 分钟才能阅读完成。

枚举类型怎么定义?

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

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

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

解法一:

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

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

解法二:

应用只读的 object 来代替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

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

先看上面例子:

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]

看出区别来了么,应用 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'>

// 取得自定义组件的 props

const 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'



// 定义只读的 ref

export 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 类型应用技巧,在此总结并分享给更多的人,感激浏览~

正文完
 0