【问题标题】:TypeScript: Infer type from discriminated union to create a map?TypeScript:从可区分的联合推断类型以创建地图?
【发布时间】:2021-09-14 09:48:56
【问题描述】:
enum ShapeType { Circle, Square }

interface Circle {
    kind: ShapeType.Circle,
    radius: number
}

interface Square {
    kind: ShapeType.Square,
    sideLength: number
}

type Shape = Circle | Square

type WhatShape<T extends ShapeType>   // <-- can we do without WhatShape?
    = T extends ShapeType.Circle ? Circle
    : T extends ShapeType.Square ? Square
    : never;

type ShapeMap = {
    [K in ShapeType]: (s: WhatShape<K>) => void
}


const handlers: ShapeMap = {
    [ShapeType.Circle]: (c: Circle) => {
        console.log(c.radius)
    },
    [ShapeType.Square]: s/*inferred!*/ => {
        console.log(s.sideLength)
    },
}

playground

这可行,但必须维护 WhatShape 以将枚举映射回形状类型有点烦人。

TS 有什么方法可以从kind 推断出我们的ShapeMap 的参数类型?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用the Extract&lt;T, U&gt; utility type 查找可分配给类型U 的联合T 的成员。在您的情况下,T 将是 discriminated union 类型 ShapeU 将是一个对象类型,其 kind 属性是您尝试映射的 ShapeType 的特定成员。所以WhatShape&lt;T&gt;可以定义为:

    type WhatShape<T extends ShapeType> = Extract<Shape, { kind: T }>
    

    它的行为与您现有的版本相同,无需与Shape 分开维护:

    type ShapeMap = {
        [K in ShapeType]: (s: WhatShape<K>) => void
    }
    /* type ShapeMap = {
        0: (s: Circle) => void;
        1: (s: Square) => void;
    } // same as before */
    

    Playground link to code

    【讨论】:

    • Extract!棒极了。谢谢,正是我想要的
    猜你喜欢
    • 1970-01-01
    • 2018-07-26
    • 2021-07-10
    • 2019-12-10
    • 2021-06-05
    • 2021-02-21
    • 1970-01-01
    • 2019-02-13
    • 2021-10-05
    相关资源
    最近更新 更多