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

时间:2019-01-26 20:07:34

标签: typescript

好的,这个有点难以解释。我的示例令人费解,但我尝试在保留错误的同时尽可能简化它。

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]类型“ any []”不能分配给类型“ UserEvents [EventName]”

两件事使我感到困惑:

  • UserEvents[EventName]应该等于any[]
  • 我正在尝试将UserEvents[EventName]分配给any[],而不是相反...

顺便说一句,此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

按预期工作。唯一失败的部分是当我要将处理程序存储在handlers中时,该处理程序应具有包含任何args列表的函数。

我意识到这有点令人困惑,所以让我知道我是否可以澄清任何事情。我很高兴深入浅出。谢谢!

1 个答案:

答案 0 :(得分:3)

原因

您遇到的错误源于使用--strictFunctionTypes标志时函数类型为contravariant in their argument type的事实。

那是什么意思?这意味着当函数期望其参数使用某种类型时,允许您使用比该期望类型更具体或更广泛的参数。

在您的情况下,handlers是通用处理程序的字典。这些处理程序需要any[]参数。他们的定义也可以这样写:

const handlers: {
  [eventName: string]: (...args: any[]) => void
} = {};

但是,您的eventHandler不仅仅是通用处理程序。它不仅接受any[]个参数,还接受UserEvents描述的一些非常具体的参数。这与矛盾的想法背道而驰-传递给函数的参数不得比其签名所要求的参数更具体。换句话说,typeof eventHandler无法分配给Handler

您可以做什么

  • 使用类型断言在本地扩展eventHandler的类型:

    handlers[eventName] = eventHandler as Handler;
    
  • 使编译器接受处理程序的特定定义:

    type Handler<T extends any[] = any> = (...args: T) => void;