14、TS中的类型推演

200 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

根据已知的信息, 计算出新的类型。

三个关键字

typeof

这里所指的 typeo f 是指书写的位置在类型约束的位置上。

有这样一种场景, b 的 类型要和 a 的类型一致, 就可以使用 typeof

const a = '123'

const b: typeof a = '123'

这里的 astring 所以 b 也是 string

typeof 作用于类时, 得到的是构造函数

class User {
    name:string = 'John';
}

function printClass(target: typeof User){

}

target: typeof User 约束改参数必须是 user 构造函数本身

keyof

keyof 作用于 类、接口、类型别名, 用于获取该类型中的所有成员名组成的联合类型。

听起来有点绕, 举个栗子马上明白

有一个约束用户类的接口

interface User {
    name:string
    age:number
    sex:string
}

假如现在要写一个打印用户对象的函数 printUser, 需要传递两个参数: 用户对象, 需要打印的属性名。

function printUser(target: User, prop: string) {
    console.log(target[prop]) //target[prop] 已经报错了
}

函数的实现看起来没有问题, 怎么会报错呢?

原因在于参数 prop的类型为string但是用户对象不一定有prop属性, 所以prop 只能传递为 name, age, sex, 因为用户对象目前只有这上三个属性,所以prop可以写为 prop: 'name' |'age' | 'sex', 很明显这样写过于繁琐所以这里应该使用keyof

function printUser(target: User, prop: keyof User) {
    console.log(target[prop])
}

in

in 经常与 keyof 联用

有这样一种场景有一个 User 接口

interface User {
    name: string
    sex: string
    age: number
}

现在有一个 类型别名需要和 User 的成员一致并且是自读的, 那么可以通过 in + keyof 实现这样一种效果

type ReadonlyUser = {
    readonly [key in keyof User]: User[key]
}

这就动态的将 User 接口的所有成员和类型都设置为只读, 并且还可以配合 泛型 变成一个通用的

type ReadonlyUser<T> = {
    readonly [key in keyof T]: T[key]
}

TS 中已经预设好的类型推演

  • Partial<T>: 将类型 T 中的成员变为可选

  • Required<T>: 将类型 T 中的成员变为必填

  • Readonly<T>: 将类型 T 中的成员变为只读

  • Exclude<T, K>: 从 T 中剔除可以赋值给 K 的成员

type T = 'a' | 'b' | 'c' | 'd'

type K = 'a' | 'e' | 'c' | 'w'

const test:Exclude<T, K> = "b" //test 只能赋值为"b" | "d"
  • Extract<T, K>: 提取 T 中可以赋值给 K 的成员

  • NonNullable<T>: 从 T 中剔除 null 和 undefined

type T = 'a' | null | 'c' | undefined

const test:NonNullable<T> = 'a' //test 只能赋值为 "a" | "c"
  • ReturnType<F>: 获取 F 类型的返回值类型
type F = (a: number, b: number) => number

const test: ReturnType<F> = 123 //test 的类型为 number
  • InstanceType<C>: 获取 C 构造函数类型的实例类型
class C {

}
const test:InstanceType<typeof C> = new C()

总结

类型演算是通过已有的类型可以做出一些自定义的类型