如何将Typescript类型对象索引用于类型化的泛型函数?

时间:2018-07-20 18:57:45

标签: typescript

我有一个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 个答案:

答案 0 :(得分:5)

当前控制流分析does not narrow generic type parameters。似乎已多次报告此问题,并用多个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属性的范围。

希望有帮助。祝你好运!

答案 1 :(得分:0)

尝试将类型存储在枚举中

export enum ApiInputTypes {
  doThis = 'doThis',
  doThat = 'doThat'
}

function handleApi(name: ApiInputTypes) {
  if(name === ApiInputTypes.doThis){
   //doThis
  }
}