我有一个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链接。
答案 0 :(得分:5)
当前控制流分析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;
};
}
该函数之所以起作用,是因为可以缩小单个nameAndArgs
变量的范围,并且在相关子句中缩小name
和args
属性的范围。
希望有帮助。祝你好运!
答案 1 :(得分:0)
尝试将类型存储在枚举中
export enum ApiInputTypes {
doThis = 'doThis',
doThat = 'doThat'
}
function handleApi(name: ApiInputTypes) {
if(name === ApiInputTypes.doThis){
//doThis
}
}