【问题标题】:How to use Typescript type object indexing for typed generic functions?如何为类型化的泛型函数使用 Typescript 类型对象索引?
【发布时间】:2021-03-12 23:21:38
【问题描述】:

我有一个从 api 名称到 api 输入对象类型的类型化映射的 api:

type ApiInputTypes = {
    doThis: { x: number }
    doThat: { y: string }
}

type ApiNames = keyof ApiInputTypes

我的目标是编写一个可以处理任何这些 api 请求的通用函数,但我遇到了一个我没想到的类型错误。

function handleApi<Name extends ApiNames>(name: Name, args: ApiInputTypes[Name]) {
    if (name === "doThis") {
        args.x // Error
    } else {
        args.y // Error
    }
 }

具有讽刺意味的是,这仍然有效......

// But this works...
handleApi("doThis", { x: 190 })

有什么想法吗?这是playground 链接。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    控制流分析目前不缩小泛型类型参数(参见microsoft/TypeScript#24085)。看起来这个问题已经被多个suggestions 多次报告以处理它。尚未实施任何事情。目前只有一些解决方法。

    一种可能的解决方法是将nameargs 打包成单个值nameAndArgs,您可以将其类型指定为两种可能情况的联合。

    type ValueOf<T> = T[keyof T];
    type NameAndArgs = ValueOf<{ [N in ApiNames]: { name: N, args: ApiInputTypes[N] } }>;
    
    function handleApi<Name extends ApiNames>(name: Name, args: ApiInputTypes[Name]) {
      const nameAndArgs = { name, args } as NameAndArgs;
      if (nameAndArgs.name === "doThis") {
        nameAndArgs.args.x // okay
      } else {
        nameAndArgs.args.y // okay
      }
    }
    

    注意NameAndArgs 属性等价于

    type NameAndArgs = {
        name: "doThis";
        args: {
            x: number;
        };
    } | {
        name: "doThat";
        args: {
            y: string;
        };
    }
    

    该函数之所以有效,是因为可以缩小单个 nameAndArgs 变量,并且 nameargs 属性在相关子句中保持缩小。

    【讨论】:

      【解决方案2】:

      尝试将类型存储在枚举中

      export enum ApiInputTypes {
        doThis = 'doThis',
        doThat = 'doThat'
      }
      
      function handleApi(name: ApiInputTypes) {
        if(name === ApiInputTypes.doThis){
         //doThis
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2019-08-23
        • 2017-08-04
        • 2021-02-22
        • 2020-05-13
        • 2021-12-30
        • 2018-07-03
        • 2021-12-06
        • 1970-01-01
        相关资源
        最近更新 更多