TypeScript函数返回类型与泛型不匹配时未抛出预期类型错误
TypeScript类型检查异常:返回undefined/null未触发预期错误
我在TypeScript中实现了registerIpcChannel函数,用于注册带指定处理器的IPC通道,处理器类型需要匹配IpcChannel接口的定义。大部分场景下类型检查正常,但当处理器故意返回undefined或null时,TypeScript未抛出预期的类型错误。
简化代码如下:
/** * Interface that describes an IPC channel * @template P - Type of the parameters for the handler * @template R - Type of the return value for the handler */ interface IpcChannel<P extends any[], R> { name: string; } /** * Function that takes in a IpcChannel interface, handler function, registers it */ const registerIpcChannel = <P extends any[], R>( ipcChannel: IpcChannel<P, R>, handler: (...params: P) => R ): void => { // Do things... }; /** * Create definition of an IPC channel * Accepts a single parameter that is a string, returns a string */ const testIpcChannel: IpcChannel<[string], string> = { name: '/foo/bar', }; // // Testing the register function // /** * Register the IPC channel * Sanity check passes, no type error is thrown. */ registerIpcChannel(testIpcChannel, (arg) => { return 'This returns a string: ' + arg; }); /** * Test with returning the wrong type * Sanity check passes, a type error is thrown because a number is returned. */ registerIpcChannel(testIpcChannel, (arg) => { return 1; }); /** * Test with returning undefined * Sanity check FAILS, this should throw a type error */ registerIpcChannel(testIpcChannel, (arg) => { return undefined; });
最后一个返回undefined的registerIpcChannel调用本应触发类型错误,但实际没有。
我尝试将handler的返回类型约束为NonNullable<R>,这样能触发返回undefined/null时的类型错误,但会破坏处理器返回void的场景:
const registerIpcChannel = <P extends any[], R>( ipcChannel: IpcChannel<P, R>, handler: (...params: P) => NonNullable<R> // + Added `NonNullable` ): void => { // Do things... }; /** * Void test * Fails, this now throws an error after adding `NonNullable` */ const voidIpcChannel: IpcChannel<[string], void> = { name: '/foo/bar', }; registerIpcChannel(voidIpcChannel, (arg) => { return; });
有意思的是,如果把处理器定义移到IpcChannel接口内部,类型检查就能正常工作,但受限于架构,必须让处理器函数与IpcChannel接口分离,所以这种方案不可行:
// // Handler on the `IpcChannel` interface // interface IpcChannel2<P extends any[], R> { name: string; handler: (...args: P) => R; } /** * Sanity check passes, a type error is thrown. */ const test: IpcChannel2<[string], string> = { name: '/foo/bar', handler: (arg) => { return undefined; }, };
内容的提问来源于stack exchange,提问作者upset-toaster
相关产品推荐
相关产品推荐

