条件类型的Typescript类型推理算法



我想学习Typescript尝试使用条件类型推断签名中的类型的算法。

示例1:这里我们正确地将T推断为number:

type Args<T> = { value: T }
function foo<T>(args: Args<T>) { return args; }
// correctly inferred as foo<number>
foo({ value: 123 });

示例2:条件类型和推断unknown

type StringOrNever<T> = T extends string ? string : never;
type Args<T> = { value: StringOrNever<T>; }
function foo<T>(args: Args<T>) { return args; }
// both calls inferred as foo<unknown> :(
foo({ value: 123 });
foo({ value: "some string" });

示例3:正确(或"预期"(推理但类型怪异的

type StringOrNever<T> = T extends string ? string : never;
type Args<T> = { value: StringOrNever<T> & T; }
function foo<T>(args: Args<T>) { return args; }
// inferred as foo<number>
foo({ value: 123 });
// inferred as foo<"Typescript">
foo({ value: "Typescript" });

我想学习的是:

  1. 为什么Typescript在示例2中为T推断unknown,以及是什么导致它像我在示例(3(中预期的那样为T推断类型
  2. 如果Typescript遵循某种通用算法来尝试推断泛型类型参数。例如,尝试一系列候选者,其中第一个候选者总是一种类型的自变量,最后一个候选者是unknown(有点像最后的手段(

泛型类型推理在TypeScript中是一个复杂的概念,有时很难理解。但泛型类型必须用于可以被给定参数的类型替换的位置。

例如1

function foo<T>(args: { value: T }) { return args; }

如果传递类型为{ value: string }的值,我们可以用string替换T

实施例2的情况并非如此。

type StringOrNever<T> = T extends string ? string : never;
function foo<T>(args: { value: StringOrNever<T> }) { return args; }

T仅用于条件的比较部分。在条件的右侧,我们只有stringneverT不在任何可以被给定类型替换的位置,因此unknown被推断为默认类型。

如果你想推理成功,你需要把T放在条件的右边。

type StringOrNever<T> = T extends string ? T : never;
function foo<T>(args: { value: StringOrNever<T> }) { return args; }

这允许TypeScript基于给定类型的value来推断T

游乐场

最新更新