首页 > 解决方案 > 当类型定义中使用泛型和条件时,Typescript 不会在 switch 语句中推断类型

问题描述

我有一个函数的类型定义。我将第二个参数的类型定义为以第一个参数的类型为条件,如下所示:

const FOO = "FOO";
const BAR = "BAR";

let fooPayload = {
    zip: "zap"
}
let barPayload = {
    cat: "dog"
}

type ActionTypes = typeof FOO | typeof BAR;
interface MyFunction<T extends ActionTypes = ActionTypes> {
  (
    action: {
      type: T;
      payload: T extends typeof FOO
        ? typeof fooPayload
        : typeof barPayload;
    }
  ): boolean;
}

接口引用的函数在其中MyFunction有一个 switch 语句,它基于切换,action.type并且根据情况,对action.payload. 这是一个例子:

const myFunction:MyFunction = (action) => {
    switch (action.type) {
        case FOO:
            action.payload.zip = "new zap"
            return true
        case BAR: 
            action.payload.cat = "new dog"
            return false
        default:
            return false
    }
}

我遇到的问题是 Typescript 没有正确推断出action.payloadswitch 语句应该是什么。例如,如果action.type等于“FOO”,那么它应该推断出action.payload必须是typeof fooPayload。相反,它推断它是typeof fooPayload | typeof barPayload.

这没有任何意义,因为 for 的类型定义action.payload基于 的值action.type,并且由于在仅当等于 "FOO"action.payload.zip时才会出现的 switch 语句中被调用,因此它应该推断 for 唯一可能的类型是。action.typeaction.payloadtypeof fooPayload

这是一个代码示例

我在这里做错了什么?

标签: typescript

解决方案


我不确定这会导致问题的确切位置,但总的来说,问题是您正在尝试重新发明打字稿已经做得很好的东西,狭窄的类型联合。

条件是一个非常有趣的特性,但有时会表现得有点出乎意料,因为它们是分布式的,因为它们超出了定义的范围。

我会以不同的方式实现它:

interface Action<T, P> {
    type: T,
    payload: P
}

type Actions 
    = Action<typeof FOO, typeof FooPayload> 
    | Action<typeof BAR, typeof BarPayload> 
    ;

interface MyFunction {
  (action: Actions): boolean;
}

不需要条件,打字稿将按预期在切换中缩小联合。


推荐阅读