keyof

返回【一个对象的属性名组成的联合】

type Obj = {
  a: number;
  b: string;
}
 
type keys = keyof Obj // 'a' | 'b'

in

取出(遍历)联合类型的每一个成员类型

type U = 'a'|'b'|'c'
 
type Obj = {
  [Prop in U]: number;
}
 
// 等同于
type Obj = {
  a: number;
  b: number;
  c: number;
}

类型映射

一个类型要基于另一个类型,不想写重复代码,可以用映射:

type A = {
  a: number;
  b: string;
  c: boolean;
}
 
type B = {
  [prop in keyof A]: A[prop] // 相当于 B 复制了一份 A
}

映射修饰符

// 增加 只读 和 可选
type MyObj<T> = {
  +readonly [P in keyof T]+?: T[P];
}
 
// 移除 只读 和 可选
type MyObj<T> = {
  -readonly [P in keyof T]-?: T[P];
}

键名重新映射

type A = {
  a: number;
  b: number;
}
 
type B = {
  [prop in keyof A as `new${prop}`]: number;
}
 
// 等价于:
type B = {
    newa: number;
    newb: number;
}

键名重新映射还可以用来进一步处理对象的属性:

type MyOmit<T, K extends keyof T> = {
  [P in keyof T as P extends K ? never : P]: T[P]
}

方括号

取出对象的键值类型,如 T[K] 会返回对象 T 的属性 K 的类型

type Obj = {
  a: number;
  b: string;
  c: boolean;
}
 
type T = Obj["a"] // number
type T = Obj["a" | "b"] // number | string
type T = Obj[keyof Obj] // number | string | boolean

取出所有值的类型:

  • 对象:obj[string]:取出所有字符串属性名的值类型的联合
  • 数组:arr[number]:取出数组中的所有值的类型的联合

条件运算

基于输入的值的类型来决定输出的值的类型:T extends U ? X : Y (即判断 T 是否为 U 的子类型)

条件类型的分配性

如果条件运算用在【泛型】中,它就变为分布式的,最终得到联合类型的结果:

type MyExclude<T, U> = T extends U ? never : T
type A = 'a' | 'b' | 'c'
type B = 'a' | 'b'
type C = MyExclude<A, B> // 'c'
// 相当于:
// type C = MyExclude<'a', B> | MyExclude<'b', B> | MyExclude<'c', B>

infer

只能在 条件运算 的 extends 子句里出现,并且只能用在条件为真的分支中。
用来在 TS 进行推断的过程中取到对应的推断值(会尝试匹配 extends 左边的类型最接近的类型),然后继续用这个变量做运算(类似正则中的捕获组)

type T0<T> = T extends infer U ? U : never
type T1 = T0<string> // string
 
type T2<T> = T extends (infer U)[] ? U : never
type T3 = T2<number[]> // number
type T4 = T2<[string, number]> // string | number

23-infer关键字_哔哩哔哩_bilibili

is

用于描述函数的返回值是 true 还是 false:parameterName is Type(左侧为当前函数的参数名,右侧为某一种类型)

typeof

用于【获取一个变量或者属性的类型】

let s = "hello"
let n: typeof s // let n: string
 
let obj = {a : 1}
let m: typeof obj.a // let m: number