繁体   English   中英

如何使用可变数量的泛型定义 TypeScript 类型

[英]How to define a TypeScript type with a variable number of generics

我正在尝试制作一个可以接受多个参数的emit函数。 此外,TypeScript 将根据第一个参数(事件)验证第二个参数及以后的参数。

我将下面的代码作为起点,但它显然不能按预期工作。

type CallbackFunc<T extends any[]> = (...args: T) => void;
interface TrackablePlayerEventMap {
    'play:other': CallbackFunc<['audio' | 'video']>;
    error: CallbackFunc<[Error, Record<string, unknown>]>;
}

const eventHandlers: Partial<TrackablePlayerEventMap> = {};

function on<K extends keyof TrackablePlayerEventMap>(event: K, callback: TrackablePlayerEventMap[K]) {
}

function emit<K extends keyof TrackablePlayerEventMap>(event: K, ...args: TrackablePlayerEventMap[K]) {
    const handler = eventHandlers[event];

    handler(...args);
}

on('error', (e, metadata) => {
    console.log(e, metadata)
});
on('play:other', x => {
    console.log(x);
});

// This should be valid
emit('error', new Error('Ouch'), { count: 5 });

// This should be invalid
emit('error', 123, 456);

为了在emit()的主体内编写handler(...args)并让它编译时没有错误,您需要利用microsoft/TypeScript#47109中引入的技术来解决我的问题如microsoft/TypeScript#30581中所述,我们将其称为“相关联合”。

第一步是想出一种将event值映射到参数列表( args数组)的类型。 就像您的TrackablePlayerEventMap类型,但属性只是参数元组类型而不是函数类型:

interface TPEventParamsMap {
    'play:other': ['audio' | 'video'],
    error: [Error, Record<string, unknown>];
}

然后我们给eventHandlers类型一个根据TPEventParamsMap显式编写的类型:

const eventHandlers: {
    [K in keyof TPEventParamsMap]?: CallbackFunc<TPEventParamsMap[K]>
} = {};

从概念上讲,这与您的Partial<TrackablePlayerEventMap>类型完全相同,但是这个类型被明确写为TPEventParamsMap上的映射类型,编译器可以使用它来跟踪event类型(类型K )和参数之间的相关性事件处理函数(类型为TPEventParamsMap[K] )。

继续:

function emit<K extends keyof TPEventParamsMap>(
    event: K,
    ...args: TPEventParamsMap[K]
) {
    const handler = eventHandlers[event];
    handler?.(...args); // okay
}

编译没有错误。 请注意,由于eventHandlersPartial ,因此它可能在 key event处没有值,因此我们使用可选的链接运算符 ( ?. )仅在该函数存在时才调用该函数。

并且从调用方的角度来看, emit()的行为也符合要求:

emit('error', new Error('Ouch'), { count: 5 }); // okay
emit('error', 123, 456); // error, 123 is not an Error

Playground 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM