Last updated on Oct 6, 2022
条件类型的语法类似于我们平时常用的三元表达式。
const value = valueA === valueB ? result1 : result2
条件类型绝大部分场景下会和泛型一起使用,泛型参数的实际类型会在实际调用时才被填充(类型别名中显式传入,或者函数中隐式提取),而条件类型在这一基础上,可以基于填充后的泛型参数做进一步的类型操作
type LiteralType<T> = T extends string ? 'string' : 'number'
type Res1 = LiteralType<'sam'> // "string"
type Res2 = LiteralType<599> // "number"
同三元表达式可以嵌套一样,条件类型中也可以多层嵌套。
type LiteralToPrimitive<T> = T extends number
? number
: T extends bigint
? bigint
: T extends string
? string
: never
条件类型也可以用来对更复杂的类型进行比较。
type Func = (...args: any[]) => any
type FunctionConditionType<T extends Func> = T extends (
...args: any[]
) => string
? 'A string return func!'
: 'A non-string return func!'
// "A string return func!"
type StringResult = FunctionConditionType<() => string>
// 'A non-string return func!';
type NonStringResult1 = FunctionConditionType<() => boolean>
// 'A non-string return func!';
type NonStringResult2 = FunctionConditionType<() => number>
这里同时存在泛型约束和条件类型,但它们产生作用的时机完全不同。
if else),相当于实际内部逻辑TypeScript 中支持通过 infer 关键字来在条件类型中提取类型的某一部分信息,比如上面我们要提取函数返回值类型:
type FunctionConditionType<T extends Func> = T extends (
...args: any[]
) => infer R
? R
: never
infer是 inference 的缩写(推断),如 infer R 中 R 就表示 待推断的类型,infer 只能在条件类型中使用。
类型结构除了函数类型结构之外,还可以是数组、接口等
// 数组
type Swap<T extends any[]> = T extends [infer A, infer B] ? [B, A] : T
type SwapResult1 = Swap<[1, 2]> // 符合元组结构,首尾元素替换[2, 1]
type SwapResult2 = Swap<[1, 2, 3]> // 不符合结构,没有发生替换,仍是 [1, 2, 3]
// 接口
type PropType<T, K extends keyof T> = T extends { [Key in K]: infer R }
? R
: never
type PropTypeResult1 = PropType<{ name: string }, 'name'> // string
type PropTypeResult2 = PropType<{ name: string; age: number }, 'name' | 'age'> // string | number
// 反转键名与键值
type ReverseKeyValue<T extends Record<string, unknown>> = T extends Record<
infer K,
infer V
>
? Record<V & string, K> // & string 可以确保属性名为 string 类型
: never
type ReverseKeyValueResult1 = ReverseKeyValue<{ key: 'value' }> // { "value": "key" }