我有一个代码片段,以前是在TypeScript 4.6中编译的,但从TypeScript 4.7(4.7,4.8,4.9)开始编译失败。如果有问题的语句不是return语句,或者lambda函数只有一个参数,而不是两个参数,那么问题就解决了。
Playground链接
import { EventEmitter } from 'node:events';
// Simplified from discord.js https://github.com/discordjs/discord.js licence Apache 2.0
interface ClientEvents {
warn: [message: string];
shardDisconnect: [closeEvent: CloseEvent, shardId: number];
}
class BaseClient extends EventEmitter {
public constructor() {
super();
};
}
type Awaitable<T> = PromiseLike<T> | T;
declare class Client extends BaseClient {
public on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => Awaitable<void>): this;
public on<S extends string | symbol>(
event: Exclude<S, keyof ClientEvents>,
listener: (...args: any[]) => Awaitable<void>,
): this;
}
// Demonstrative code
const bot = new Client();
// Return statement. Fails to compile, thinks that event is a union type of all first arguments (string | CloseEvent), but hovering over `event` shows just CloseEvent.
bot.on("shardDisconnect", (event, shard) => console.log(`Shard ${shard} disconnected (${event.code},${event.wasClean}): ${event.reason}`));
// Not a return statement. Compiles.
bot.on("shardDisconnect", (event, shard) => {
console.log(`Shard ${shard} disconnected (${event.code},${event.wasClean}): ${event.reason}`);
});
// Return statement. Compiles.
bot.on("shardDisconnect", event => console.log(`${event.code} ${event.wasClean} ${event.reason}`))
1条答案
按热度按时间eqqqjvef1#
看起来您可能遇到了与分布式条件类型相关的bug。
ClientEvents[keyof ClientEvents]
的类型是[message: string] | [closeEvent: CloseEvent, shardId: number]
。虽然IDE似乎正确地认识到您的args应该是event, shardId
,因为您已经将K
区分为shardDisconnect
,在某个时刻,解析器失去了该辨别,并且认为第一个参数是string | CloseEvent
类型(这是来自warn和shardDisconnect的第一个参数的并集)。看起来你可以通过使用条件类型作为参数类型来解决这个问题,这可以正确地重新缩小K:
但是,如果你使用的是条件类型,你可以摆脱你的重载:
我完全不知道为什么回调返回void或不改变行为。这听起来像是值得作为Typescript项目的一个问题打开的东西。
Playground链接