typescript - 在打字稿的列表中映射正确函数的函数签名
问题描述
我正在构建一个消息格式化程序,它可以构建一堆不同类型的消息。根据它正在构建的消息类型,将调用不同的渲染函数。这些函数中的每一个都可以接受不同的参数或可选参数。
我在设置这个并且让打字稿理解我在做什么时遇到了麻烦。
这是一些杂乱的代码,可以让您了解我所追求的。
export enum MessageType {
Greeting,
Warning,
}
getFormattedMessage(messageType:MessageType, ...messageParams): string {
const messageBuilders: {[K in MessageType]: () => string} = {
[MessageType.Greeting]: () => 'Hi There',
[ErrorType.Warning]: ({name}) =>
name ? `${name} is required` : 'That thing is required',
}
return messageBuilders[messageType](...messageParams)
}
getFormattedMessage(MessageType.Greeting)
// output, "Hi There
getFormattedMessage(MessageType.Warning)
// output, "That thing is required"
getFormattedMessage(MessageType.Warning, {name: "A fancy hat"})
// output, "A fancy hat is required"
上面的代码有一些问题。例如,我在为getFormattedMessage
或正确设置打字稿签名时遇到了麻烦messageBuilders
。
我想达到一个点,如果我getFormattedMessage(MessageType.Warning,
在我的编辑器中输入,vsCode 会建议显示在附加到Warning
类型的渲染函数的签名中的变量,依此类推。
非常感谢!
解决方案
这里使用了一个辅助标识函数newMessageBuilder
,让编译器隐式推断 messageBuilder 的类型,同时约束其类型的下限;然后根据 的值Parameters<(typeof messageBuilders)[K]>
来约束 的类型。messageParams
messageType
export enum MessageType {
Greeting,
}
export enum ErrorType {
Warning = 1,
}
function newMessageBuilder<T extends {[K in MessageType | ErrorType]: (...messageParams: any[]) => string}>(messageBuilders: T) { return messageBuilders; }
const messageBuilders = newMessageBuilder({
[MessageType.Greeting]: () => 'Hi There',
[ErrorType.Warning]: ({name}: {name: string}) =>
name ? `${name} is required` : 'That thing is required',
});
function getFormattedMessage<K extends MessageType | ErrorType>(messageType: K, ...messageParams: Parameters<(typeof messageBuilders)[K]>) {
return (messageBuilders[messageType] as any)(...messageParams);
}
getFormattedMessage(MessageType.Greeting)
// output, "Hi There
// ERROR Argument of type '{ a: number; }' is not assignable to parameter of type '{ name: string; }'.
// Object literal may only specify known properties, and 'a' does not exist in type '{ name: string; }'.(2345)
getFormattedMessage(ErrorType.Warning, {a:1})
// output, "That thing is required"
getFormattedMessage(ErrorType.Warning, {name: "A fancy hat"})
// output, "A fancy hat is required"
当然,上述问题仍然存在(messageBuilders[messageType] as any)
我忽略的问题,因为我发现没有解决方案留给读者作为练习。