feature in ts
distributive when spread tuple
[1, ...([2, 3] | [4, 5])]
equals [1, 2, 3] | [1, 4, 5]
avoid distribution
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
// 'StrArrOrNumArr' is no longer a union.
type StrArrOrNumArr = ToArrayNonDist<string | number>;
由于 union 在 conditional type 中会被拆开,所以我们无法通过 U extends never ? ... : ...
的方式来判断是否是空 union,因为空 union 没有元素,会被整体跳过,得到 never
。
我们可以利用上述特性来实现这一目的:
type IsNever<U> = [U] extends [never] ? true : false;
Ref: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
no-op for any index signature
在对 interface 进行 assignability 检查时,会跳过 value type 为 any
的项。
所以,type1 extends { [key in keyof type2]: any }
几乎等价于 type1 extends {}
。
type test1 = (() => void) extends { [key: string]: any } true : false; // true
type test2 = ([1, 2, 3]) extends { [key: string]: any } true : false; // true
type test3 = (() => void) extends { [key: string]: unknown } true : false; // false
type test4 = ([1, 2, 3]) extends { [key: string]: unknown } true : false; // false
存在一个例外,原始类型可以 assign to {}
,but not Record<any, any>
。
- 我们可以使用
Record<any, any>
区分原始类型和其他类型:
type test1 = [1, 2, 3] extends Record<any, any> ? true: false; // true
type test2 = (() => void) extends Record<any, any> ? true: false; // true
type test3 = { } extends Record<any, any> ? true: false; // true
type test4 = { a: 'b', c: 2 } extends Record<any, any> ? true: false; // true
type test5 = '1' extends Record<any, any> ? true: false; // false
type test6 = 1 extends Record<any, any> ? true: false; // false
type test7 = true extends Record<any, any> ? true: false; // false
- 可以使用
Record<any, unknown>
来区分 interface 和 tuple/function:
type test1 = [1, 2, 3] extends Record<any, unknown> ? true: false; // false
type test2 = (() => void) extends Record<any, unknown> ? true: false; // false
type test3 = { } extends Record<any, unknown> ? true: false; // true
type test4 = { a: 'b', c: 2 } extends Record<any, unknown> ? true: false; // true
ref:
type-challenges - deepreadonly
readonly tuple
如何得到一个 readonly tuple:
type ReadonlyTuple<T extends any[] | []> = {
readonly [key in keyof T]: T[key]
}