一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
中等
AnyOf
type AnyOf<T extends readonly any[]> =
T[number] extends ('' | 0 | false | [] | { [key: string]: never })
? false
: true;
通过索引访问类型可以获取数组中所有元素的联合类型,例如:
type a<T extends readonly any[]> = T[number]
// type b = 3 | 1 | 2
type b = a<[1, 2, 3]>
为了识别出一个空的字面量类型,所以通过声明一个对象类型,并且在里面将值的类型设置为never,也就是:
{
[key: string]: never
}
// 也可以使用内置类型来声明
Record<string, never>
IsNever
type IsNever<T> = [T] extends [never] ? true : false;
使用泛型 + 条件判断时,如果传入的值是联合类型,会出现分布,例如:
type IsNever<T> = T extends never ? true : false;
type a = IsNever<never | string>;
// 相当于
type a = never extends never ? true : false | string extends never ? true : false
上面发生分布的时确定的值是never | string,never是永远不存在的值,它会丢失,为了不让IsNever发生分布的行为,就需要在extends左右两侧的类型上加上[],让它变为一个元组类型,或者直接变成一个数组类型也可以(T[])。
IsUnion
type IsUnion<T, B = T> = T extends B ? [B] extends [T] ? false : true : never;
答案参考自解答区,👍比较多的一个,也比较简洁。
刚开始看到这个答案还是有点懵的,然后把每个case都分析了一遍就明白了。里面的知识主要涉及到条件类型。
我们通过挑战中的case来看看:
第一种:T不是联合类型的。
// case 如下,期望 false
Expect<Equal<IsUnion<string>, false>>
// 1.代入到类型中
type IsUnion<string, B = string> =
string extends string
? [string] extends [string]
? false
: true
: never;
// 2.string extends string 为 true,进入第二个表达式:
[string] extends [string] ? false : true
// 3.第二步的表达式成立,所以最后返回结果为:true
IsUnion<string> == true
第二种: T为一般的联合类型:
// case 如下,期望 true
Expect<Equal<IsUnion<'a' | 'b'>, true>>
// 1.由于 T 为联合类型,所以会发生分布的行为
'a' extends 'a' | 'b'
? ['a' | 'b'] extends ['a']
? false
: true
: never
|
'b' extends 'a' | 'b'
? ['a' | 'b'] extends ['b']
? false
: true
: never;
// 2.执行完第 1 步后的结果为:
true | true
true // 最终就是 true
第三种: T为特殊的联合类型:
// case 如下,期望 false
Expect<Equal<IsUnion<string | never>, false>>
// never 是永远不存在的值,在联合类型中,它不是一个有效的值
// 例如下面 T 的类型就是 stirng
type T = string | never;
// 所以上面的 case 可以看做:
Expect<Equal<IsUnion<string | never>, false>> == Expect<Equal<IsUnion<string>, false>>