Typescript:如何用泛型动态地描述对象键?

f45qwnt8  于 2023-05-01  发布在  TypeScript
关注(0)|答案(1)|浏览(146)

我试图描述一个事件处理程序的字典(具有不同的有效负载形状),如下所示:

type Events = 'foo' | 'bar';

type EventsPayload = { foo: string, bar: number };
type EventHandler<Event extends Events> = (args: EventsPayload[Event]) => void;

const eventHandlers: { [Event in Events]?: EventHandler<Event> } = {};
export function addEventHandler<Event extends Events>(
  name: Event,
  handler: EventHandler<Event>,
) {
  eventHandlers[name] = handler;
}

这给了我一个错误:
类型“EventHandler”不能分配给类型“{ foo?:EventHandler〈“foo”〉|undefined; bar?:EventHandler〈“bar”〉|undefined; }[事件]'。
如果我在插入处理程序方法时删除泛型,它会起作用:

eventHandlers.foo = (payload: string) => {};
8dtrkrch

8dtrkrch1#

在定义handler参数的类型时,可以通过引用eventHandlers的类型来使其工作。(例如,这就是它们对lib.dom.d.ts中的addEventListener所做的。)我发现最简单的方法是为eventHandlers对象的类型使用类型别名:

type Events = "foo" | "bar";

type EventsPayload = { foo: string; bar: number };
type EventHandler<Event extends Events> = (args: EventsPayload[Event]) => void;

// *** Define the type
type EventHandlers = {
    [Event in Events]?: EventHandler<Event>;
};

const eventHandlers: EventHandlers = {};

// *** Use it for `handler`
export function addEventHandler<Event extends Events>(
    name: Event,
    handler: EventHandlers[Event]
) {
    eventHandlers[name] = handler;
}

Playground链接
实际上,你并不需要**来拥有类型别名,但是,你可以使用typeof eventHandlers来代替:

type Events = "foo" | "bar";

type EventsPayload = { foo: string; bar: number };
type EventHandler<Event extends Events> = (args: EventsPayload[Event]) => void;

const eventHandlers: { [Event in Events]?: EventHandler<Event> } = {};
export function addEventHandler<Event extends Events>(
    name: Event,
    handler: typeof eventHandlers[Event]
) {
    eventHandlers[name] = handler;
}

Playground链接
主观地说,对我来说,如果我们有一个类型别名来工作,那就更清楚了。

相关问题