代码之家  ›  专栏  ›  技术社区  ›  Chet

如何使用类型化泛型函数的Type Script类型对象索引?

  •  1
  • Chet  · 技术社区  · 7 年前

    我有一个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 链接。

    2 回复  |  直到 7 年前
        1
  •  5
  •   jcalz    7 年前

    当前控制流分析 does not narrow generic type parameters 是的。看来这个问题已经被多次报道了 suggestions 为了处理它什么都还没有实施。目前只有解决办法。

    一种可能的解决方法是打包 name args 变成一个单一的值 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;
        };
    }
    

    这个函数起作用是因为 名称和参数 变量可以缩小,并且 名称 参数 在相关条款中,财产的范围缩小了。

    希望能有所帮助。祝你好运!

        2
  •  0
  •   andrew ferguson    7 年前

    尝试将类型存储在枚举中

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