TypeScript:推断嵌套联合类型的类型

Posted

技术标签:

【中文标题】TypeScript:推断嵌套联合类型的类型【英文标题】:TypeScript: Infer type of nested union type 【发布时间】:2018-07-26 21:42:34 【问题描述】:

我正在使用 TypeScript 中的对象,这些对象可能包含可以获取数据或数据本身的惰性链接。这就是为什么这些属性得到一个联合类型 T |字符串。

现在我想编写一个类型安全的解析函数来解析返回嵌套类型的嵌套属性。

type TypeOrString<T> = T | string;


interface A 
    propA: TypeOrString<B>;


interface B 
    propB: TypeOrString<any[]>;



function resolve<T, K1 extends keyof T, K2 extends keyof T[K1]>
(data: T | string, p1: K1, p2: K2): T[K1][K2] 
    return null;


let a:A;
let b:TypeOrString<any[]> = resolve(a, "propA", "propB");

//Error TS2345: Argument of type '"propB"' is not assignable 
//to parameter of type '"toString" | "valueOf"'.

但是编译器给了我一个错误,TS2345:'"propB"' 类型的参数不可分配给'"toString" 类型的参数 | “的价值”'。是否有机会从接口 A 的实例推断 propB 的类型?

【问题讨论】:

【参考方案1】:

您可以通过使用recursive mapped types 来模拟以下事实:不仅是“数据或字符串”,而且数据本身就是“数据或字符串”,从而获得您正在寻找的东西。像这样:

type DeepTypeOrString<T> = string | 
  [K in keyof T]: DeepTypeOrString<T[K]>

这主要为您提供了您想要的原始类型和普通对象类型。数组是另一回事,但一旦 conditional types 功能在 TypeScript 2.8 中落地,这将被清除。

现在让我们通过您期望它们与“可能是字符串”版本相反的实际数据来定义AB

interface A  
  propA: B

interface B 
  propB: any[]

您的resolve() 函数与之前类似,只是data 被声明为DeepTypeOrString&lt;T&gt; 类型:

declare function resolve<T, K1 extends keyof T, K2 extends keyof T[K1]>(
  data: DeepTypeOrString<T>, p1: K1, p2: K2
): T[K1][K2];

现在当您调用resolve() 时,您将看到您期望的推理:

declare const a: DeepTypeOrString<A>;
const ret = resolve(a, 'propA', 'propB') // ret is inferred as any[]

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

【讨论】:

以上是关于TypeScript:推断嵌套联合类型的类型的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 学习笔记 — 类型推断和类型保护

访问从 GraphQL 生成的多个嵌套 TypeScript 类型

获取 TypeScript 中双嵌套对象的所有值类型

TypeScript 基础类型

TypeScript——类型检查机制

Typescript快速入门