简体   繁体   English

来自泛型类型的查找类型不能分配给“任何”

[英]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[]
  • I'm trying to assign 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.

相关问题 const 断言似乎无法将类型分配给泛型参数的类型 any[] - The const assertion seems that the type can't be assigned to the type any[] for the generic parameter void 类型的 Function 不能分配给 Observable 类型<any></any> - Function of type void can't be assigned to type Observable<any> 实用程序类型 (Extract) 与泛型 (keyof T) 一起提供了无法分配任何内容的类型 - Utility type (Extract) in conjunction with generic (keyof T) gives type that nothing can be assigned to 为什么任何可以分配给 TypeScript 中的每种类型 - Why can any be assigned to every type in TypeScript 为什么不能将 document.createElement 的返回类型分配给仅限于 HTMLElement 的泛型? - Why can't the return type of document.createElement be assigned to a generic that's restricted to HTMLElement? 为什么映射类型不能使用通用但有限的键完全解析查找? - Why can’t a mapped type fully resolve a lookup using a generic, but finite, key? 在 function 中使用泛型类型返回类型“任何 []”不可分配给类型“T” - Use generic type in function returns Type 'any[]' is not assignable to type 'T' 你能让 TS 从被赋值的值中推断出变量的泛型类型 arguments 吗? - Can you make TS infer a variable's generic type arguments from those on the value being assigned? 为什么不先显式地强制将“ any”分配给任何类型? - Why can 'any' be assigned to any type without explicitly casting it first? 类型“any [] | undefined”不能分配给类型“any []” - the type "any [] | undefined" cannot be assigned to the type "any []"
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM