[英]Lookup type from generic type can't be assigned to “any”
Alright, this one is a bit hard to explain. 好吧,这个有点难以解释。 My example is convoluted but I tried to simplify it as much as possible while retaining the error.
我的例子很复杂,但我试图尽可能地简化它,同时保留错误。
type Handler = (...args: any[]) => void;
const handlers: { [eventName: string]: Handler } = {};
type Events = {
// Map event signature (arg types) to event name
[eventName: string]: any[];
};
function createOnEvent<UserEvents extends Events>() {
type ValidEventName = Extract<keyof UserEvents, string>;
return <EventName extends ValidEventName>(
eventName: EventName,
eventHandler: (...args: UserEvents[EventName]) => void,
) => {
handlers[eventName] = eventHandler; // [0] ERROR HERE
};
}
[0] Type 'any[]' is not assignable to type 'UserEvents[EventName]'
[0]类型'any []'不能分配给'UserEvents [EventName]'
Two things confuse me: 有两件事令我困惑:
UserEvents[EventName]
should be equal to any[]
UserEvents[EventName]
应该等于any[]
UserEvents[EventName]
to any[]
, not the other way around... UserEvents[EventName]
分配给any[]
,而不是相反... Btw, this is how this API is used: 顺便说一下,这是这个API的使用方式:
type FooEvents = {
eventOne: [number];
eventTwo: [string, boolean];
};
const onEvent = createOnEvent<FooEvents>();
onEvent('eventOne', (arg1: number) => null); // OK
onEvent('eventTwo', (arg1: string, arg2: boolean) => null); // OK
onEvent('eventOne', (arg1: string) => null); // error
Which works as expected. 哪个按预期工作。 The only part that fails is when I want to store the handler in
handlers
, which should expect functions with any list of args. 失败的唯一部分是当我想将处理
handlers
存储在处理handlers
,它应该期望具有任何args列表的函数。
I realize this is a bit confusing, so let me know if I can clarify anything. 我意识到这有点令人困惑,所以如果我能澄清任何事情,请告诉我。 I'd be great to get to the bottom of this.
我很高兴能够深究这一点。 Thanks!
谢谢!
Reason 原因
The error you experience stems from the fact that function types are contravariant in their argument type when the --strictFunctionTypes
flag is used. 您遇到的错误源于这样的事实:当使用
--strictFunctionTypes
标志时,函数类型在其参数类型中是逆变的 。
What does that mean? 这意味着什么? It means when a function expects some type for its argument, you are allowed to use an argument as specific or wider than that expected type.
这意味着当函数期望其参数具有某种类型时,您可以使用特定参数或比预期类型更宽的参数。
In your case, handlers
is a dictionary of generic handlers. 在您的情况下,
handlers
是通用处理程序的字典。 These handlers expect any[]
arguments. 这些处理程序期望
any[]
参数。 Their definition could as well have been written like that: 他们的定义也可以写成:
const handlers: {
[eventName: string]: (...args: any[]) => void
} = {};
However, your eventHandler
is not just a generic handler. 但是,您的
eventHandler
不仅仅是一个通用的处理程序。 It does not accept just any[]
arguments, but some very specific ones described by UserEvents
. 它不接受
any[]
参数,而是接受UserEvents
描述的一些非常具体的参数。 That's against the idea of contravariance — arguments passed to a function must not be more specific than the ones required by its signature. 这违背了逆向的观点 - 传递给函数的参数不能比其签名所要求的更具体。 In other words,
typeof eventHandler
is not assignable to Handler
. 换句话说,
typeof eventHandler
不能分配给Handler
。
What you can do 你可以做什么
Widen the type of eventHandler
locally by using a type assertion: 通过使用类型断言在本地
eventHandler
的类型:
handlers[eventName] = eventHandler as Handler;
Make the compiler accept specific definitions of a handler: 使编译器接受处理程序的特定定义:
type Handler<T extends any[] = any> = (...args: T) => void;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.