semlinker/awesome-typescript

「重学TS 2.0 」TS 练习题第二十六题

Opened this issue · 11 comments

实现一个 IsNever 工具类型,判断指定的类型是否为 never 类型。具体的使用示例如下所示:

type I0 = IsNever<never> // true
type I1 = IsNever<never | string> // false
type I2 = IsNever<null> // false

请在下面评论你的答案。

type IsNever<T> = [T] extends [never] ? true : false;
type I0 = IsNever<never> // true
type I1 = IsNever<never | string> // false
type I2 = IsNever<null> // false
type IsNever<T> = [T] extends [never] ? true : false;

type I0 = IsNever<never>; // true
type I1 = IsNever<never | string>; // false
type I2 = IsNever<null>; // false
type IsNever<T> = (T extends never ? true : false) extends never ? true : false;

type II0 = IsNever<never> // true
type II1 = IsNever<never | string> // false
type II2 = IsNever<null> // false
type II3 = IsNever<{}> // false
type II4 = IsNever<[]> // false
type II5 = IsNever<[] | never> // false

[] 包裹 T,否则泛型参数会被当成一个裸类型处理,走 '条件式分布类型' 的判断逻辑,当泛型参数是 any 这种特殊值时,会得到分布后的类型

type IsNever<T> = [T] extends [never] ? true : false

type t1 = IsNever<any>
type t2 = IsNever<never>
type t3 = IsNever<1 | 'dog'>

之前看到过一个其他人写的,感觉很强

type IsEqual<T, U> = (<S>() => S extends T ? 1 : 0) extends (<S>() => S extends U ? 1 : 0) ? true : false

type IsNever<T> = IsEqual<T, never>

解题

type IsNever<T> = [T] extends [never] ? true : false;

type II0 = IsNever<never> // true
type II1 = IsNever<never | string> // false
type II2 = IsNever<null> // false
type II3 = IsNever<{}> // false
type II4 = IsNever<[]> // false
type II5 = IsNever<[] | never> // false

解析

这边 [T][never]元组,作为包装类型,如果联合类型被包装过,就不会被展开。
另外,因为 never 类型不能扩展 never 类型,但是 never[] 可以扩展 never[]

详细可以看文档介绍:https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types

也可以看这个例子:

type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr = ToArray<string | number>;   // type StrArrOrNumArr = string[] | number[]

type ToArray2<Type> = [Type] extends [any] ? Type[] : never;
type StrArrOrNumArr2 = ToArray2<string | number>;  // type StrArrOrNumArr2 = (string | number)[]
type IsNever<T> = [T] extends [never] ? true : false // 你的实现代码
// type IsNever<T> = T extends never ? true : false // 第二个

type I0 = IsNever<never> // true 用第二个是never
type I1 = IsNever<never | string> // false
type I2 = IsNever<null> // false
type I3 = IsNever<any> // false 用第二个是boolean
type I4 = IsNever<string> // false

??为什么I0和I3用第二个方法结果是never和boolean

// 实现一个 IsNever 工具类型,判断指定的类型是否为 never 类型。具体的使用示例如下所示:
type IsNever<T> = [T] extends [never] ? true : false;

type I0 = IsNever<never> // true
type I1 = IsNever<never | string> // false
type I2 = IsNever<null> // false

知识点 : never 是一个联合类型,因此要通过 [T] 将其变成普通类型,再去 extends

@xiaoYuanDun 既然都通过返回值了为什么不直接 type IsEqual<T, U> = (() => T) extends (() => U) ? true : false

@xiaoYuanDun 既然都通过返回值了为什么不直接 type IsEqual<T, U> = (() => T) extends (() => U) ? true : false

你这种写法,不能判断IsEqual<any,1>这种的包含any类型的判断。
原因是any类型和任何类型都会判为一样。