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

标签 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>

我试图稍微简化一下,并提出了以下示例。条件类型返回 number当给出 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

但是,两个 return 语句都显示相同的错误:
Type '42' is not assignable to type 'Return<T>'.(2322)
Type '"Hello World!"' is not assignable to type 'Return<T>'.(2322)

我在这里缺少什么?

最佳答案

这就是它不起作用的原因:Typescript 确实 control-flow type narrowing在常规变量上,而不是像您的 T 这样的类型变量上.打字机typeof x === "string"可用于缩小变量x输入 string ,但不能缩小T成为 string ,并没有尝试。

这是有道理的,因为 T可能是联合类型 string | number即使 x是一个字符串,所以缩小 T 是不合理的本身,或缩小T的上限。理论上缩小范围是合理的T类似于“扩展 string | number 但其与 string 的交集不是 never 的类型”,但这会为类型系统增加非常多的复杂性,但 yield 相对较小。除了使用类型断言之外,没有完全通用的方法。例如,在您的代码中,return 42 as Return<T>; .

也就是说,在您的用例中,您根本不需要通用函数;你可以只写两个 overload signatures :

// 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!";
  }
}

Playground Link

关于typescript - 通用类型扩展联合不会被类型保护缩小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60475431/

相关文章:

javascript - 子路由中的 routerLink 错误

typescript - 如何将元组类型转换为联合?

typescript - getter 和 setter 具有不同类型的索引签名

typescript - 如何创建每个值的类型取决于键的查找?

visual-studio-2012 - 在现有 Visual Studio 网站项目中使用 TypeScript

reactjs - React TypeScript onSubmit e.preventDefault() 不起作用

reactjs - useReducer 中返回参数的通用类型

typescript - Typescript 中的多种类型谓词

Typescript:条件通用类型

typescript - 从类型中删除 undefined