我认为一个例子胜过千言万语,所以下面是我要做的:
type Message = keyof MessageArguments;
type MessageArguments = {
'foo': []
'bar': {}
};
type MsgEvent<T extends Message> = {
data: {
type: T
arguments: MessageArguments[T]
}
};
type FunctionTypes = {
[K in Message]: (event: MsgEvent<K>) => void
}
const functions: FunctionTypes = {
'bar': (event) => {
console.log("invoked bar", event);
},
'foo': (event) => {
console.log("invoked foo", event);
}
};
function is<T extends Message>(e: MsgEvent<T>, type: T): e is MsgEvent<T> {
return e.data.type === type;
}
function invoke<T extends Message>(e: MsgEvent<T>, type: T): FunctionTypes[T] {
if (is(e, type)) {
return functions[e.data.type](e);
} else {
throw "failed to find function";
}
}
invoke({
data: {
type: 'foo',
arguments: []
}
}, 'foo');
如果将其输入到typescript操场或编译器中,将得到一个错误:
Cannot invoke an expression whose type lacks a call signature. Type '((event: MsgEvent<"foo">) => void) | ((event: MsgEvent<"bar">) => void)' has no compatible call signatures.
(property) type: T extends "foo" | "bar"
但是从代码中可以清楚地看出只有方法(或者没有)可以被调用,并且我认为类型应该能够表示,但是我不知道如何…这就像我需要告诉编译器在
function invoke<T extends Message>
中,T
是一个异或-它只能是其中一个值,不能是任何一个。 最佳答案
按照Titian Cernicova Dragomir所说的,编译器不知道你没有用invoke
调用T = "foo" | "bar"
。因此,它只能基于T
的约束"foo" | "bar"
进行推理。编辑:我刚刚更新了an existing suggestion of mine以覆盖约束类型变量SuntLon;我建议您投票表决。
关于typescript - 在TypeScript中以类型安全的方式调用函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51994258/