修正了一个最小的例子。 Playground link
// Adapted from https://github.com/abalabahaha/eris, licence MIT
// Not exported
interface ClientEvents<T> {
(event: "ready", listener: () => void): T;
(event: "connect", listener: (id: number) => void): T;
(event: "error", listener: (message: string) => void): T;
// needed or TypeScript will take the one above as the definition in the first example
(event: string, listener: (...args: any[]) => void): T;
}
export declare class Client {
on: ClientEvents<this>;
}
////////////////////////////////////////////////////// Separate module
// The declarations above are expected to be used like this
const client = new Client();
// Types are correctly inferred for each handler
client.on("ready", () => console.log("hello world!"));
client.on("connect", id => console.log(id));
// Example: this falls back to the generic declaration and all typings are lost for each function,
// unlike directly calling Client.on above
const listeners: Record<Parameters<Client["on"]>[0], Parameters<Client["on"]>[1]> = {
ready: () => console.log("hello world!"),
connect: id => console.log(id)
}
// Missing: Destructure to extract the parameters of Client.on
const handlers: Record<Destructure<Parameters<Client["on"]>>> = {
// The goal is that TypeScript should figure out what the typings for each of these functions should be
ready: () => console.log("hello world!"),
connect: id => console.log(id),
error: msg => console.warn(msg)
};
// Then maybe something like this would work and still be type-safe
// for (const event in handlers) {
// client.on(event, handlers[event]);
// }
修改前的原件
情况:Eris.Client.prototype.on
是一个接受两个参数的方法。
我已经设法声明了一个 Record<Parameters<Eris.Client["on"]>[0], Parameters<Eris.Client["on"]>[1]>
类型,但是分离的参数意味着参数之间的任何关系都不会被捕获并且都回退到它们最通用的状态。也就是说,如果可以根据第一个参数的类型缩小第二个参数的类型,这将无法捕获它,这里提取的类型是所有可能类型的联合。
是否可以实现某种类型 Destructure
以便我可以声明类型 Record<Destructure<Parameters<Eris.Client["on"]>>>
?