如何有条件地检测 TypeScript 中的“任何”类型?

How to conditionally detect the `any` type in TypeScript?

我想要一个可以用作 IsStrictlyAny<T> 的实用程序,如果 T 正好是 any,它将解析为 true 类型,并且解析为 false 否则键入。我该怎么做?

我的第一个想法:

type IsStrictlyAny<T> = any extends T ? true : false;

结果:

这是个好问题,一开始我觉得不可能,但经过一番调查,我认为有办法。

首先,检查一下:

type Test = any extends never ? 'A' : 'B' // "A" | "B"

这意味着打字稿知道 any 可以是任何东西,因此它无法决定条件的哪一边到 return,所以它的两边都是 return一个工会。我相当确定 any 是唯一会以这种方式表现的情况。

那么您只需要尝试检测联合是 returned 还是单个值。为此,我们使用了两个工具。

首先,注意两个不兼容类型的交集是never

type Test = 'A' & 'B' // never

这是有道理的,因为一个值不能同时是两个不同的字符串。

其次,如果我们可以获得类型联合的所有成员的交集,我们就可以测试它是否是 never,或者它是否是任何其他有效类型。 有个帮手把并集转交集,我就不解释了。

所以对一些人来说:

  1. 检查是否将 return 条件的两边都键入为并集
  2. 将并集成员合并成一个交集,看结果是不是never
// From: 
type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

// If T is `any` a union of both side of the condition is returned.
type UnionForAny<T> = T extends never ? 'A' : 'B'

// Returns true if type is any, or false for any other type.
type IsStrictlyAny<T> =
  UnionToIntersection<UnionForAny<T>> extends never ? true : false

type A = IsStrictlyAny<any>     // true
type B = IsStrictlyAny<string>  // false
type C = IsStrictlyAny<unknown> // false

Playground

表达式:

type IsStrictlyAny<T> = (T extends never ? true : false) extends false ? false : true;

符合条件:

type IsStrictlyAny<T> = (T extends never ? true : false) extends false ? false : true;

type t1 = IsStrictlyAny<any>;     // true
type t2 = IsStrictlyAny<unknown>; // false
type t3 = IsStrictlyAny<string>;  // false
type t4 = IsStrictlyAny<never>;   // false!

Playground.


这是有效的,因为 T extends never ? true : falsetreated as a distributed conditional type 解析为:

  • boolean 如果 Tany
  • never 如果 Tnever.
  • false 如果 T 是别的。

然后由于 neverfalse 都可以分配给 false,因此只有当 T 时,最终表达式 (...) extends false ? false : true 才是 trueany.

我找到的最简单的答案是 , and the explanation is in :

的答案
type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N; 
type IsAny<T> = IfAny<T, true, false>;

type A = IsAny<any>; // true
type B = IsAny<unknown>; // false
type C = IsAny<string>; // false
type D = IsAny<never>; // false

这有效的一个简短原因是 0 extends (1 & T) 对于 "plays by the rules" 的任何类型 T 应该为假。 0 不能分配给 1 所以它真的不应该分配给 1 & T 不管 T 是什么。但是 any 不遵守规则:1 & any 的计算结果为 any,而 0 extends any 为真。

希望对您有所帮助;祝你好运!

Playground link to code