通用类型扩展联合不会被类型保护缩小

phi*_*ole 7 typescript typescript-generics

我试图复制 Anders 在Build 2018 (36:45) 上展示的条件类型和泛型示例。他使用条件类型作为返回类型来替代更传统的函数重载。

幻灯片有以下内容:

type Name = { name: string };
type Id = { id: number };
type Check = { enabled: boolean };

type LabelForType<T> =
  T extends string ? Name :
  T extends number ? Id :
  T extends boolean ? Check :
  never;

declare function createLabel<T extends string | number | boolean>(value: T): LabelForType<T>
Run Code Online (Sandbox Code Playgroud)

我试图稍微简化一下,并提出了以下示例。条件类型number在给定 a 时返回,string反之亦然,而函数将此条件类型实现为返回类型。

type Return<T> = T extends string ? number : T extends number ? string : never;

function typeSwitch<T extends string | number>(x: T):  Return<T>{
  if (typeof x == "string") {
    return 42;
  } else if (typeof x == "number") {
    return "Hello World!";
  }
  throw new Error("Invalid input"); // needed because TS return analysis doesn't currently factor in complete control flow analysis
}

const x = typeSwitch("qwerty"); // number
Run Code Online (Sandbox Code Playgroud)

但是,两个 return 语句都显示相同的错误:

Type '42' is not assignable to type 'Return<T>'.(2322)
Type '"Hello World!"' is not assignable to type 'Return<T>'.(2322)
Run Code Online (Sandbox Code Playgroud)

我在这里缺少什么?

kay*_*ya3 9

这也是为什么它不工作:打字稿确实控制流型变窄定期变量,但不能在类型变量喜欢你T。类型保护typeof x === "string"可用于将变量缩小x为 type string,但不能缩小Tstring,并且不尝试。

这是有道理的,因为即使是字符串T也可能是联合类型,因此缩小自身或缩小的上限是不合理的。从理论上讲,将范围缩小到诸如“一种扩展但与它的交集不是”之类的内容是合理的,但这会为类型系统增加非常多的复杂性,而收益相对较小。除了使用类型断言之外,没有完全通用的方法。例如,在您的代码中,.string | numberxTTTstring | numberstringneverreturn 42 as Return<T>;

也就是说,在您的用例中,您根本不需要通用函数;你可以只写两个重载签名

// overload signatures
function typeSwitch(x: string): number;
function typeSwitch(x: number): string;
// implementation
function typeSwitch(x: string | number): string | number {
  if (typeof x === "string") {
    return 42;
  } else {
    // typeof x === "number" here
    return "Hello World!";
  }
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

  • 也许这是我缺乏理解性的说法,但如果我必须向编译器断言事物实际上是我所知道的类型,那么这一切还有什么意义呢?它比我只用 switch 语句编写一个普通的旧函数并断言返回类型更类型安全吗?这一切给我们带来了什么? (2认同)