如何在TypeScript中从函数返回类型排除特定类型?
解决TypeScript中排除函数返回特定类型的问题
想要定义函数类型,限制其返回值不能是Promise、Observable这类包装类型,仅允许返回普通的Record<string, any>对象。尝试了以下写法但无法生效:
type FooFn = { <T extends Record<string, any>>(): T extends Promise<any> ? never : T; }; const foo: FooFn = () => ({ 'ok': 'ok' }); // 期望正常工作 const foo2: FooFn = () => { return Promise.resolve({ 'ok': 'ok' }) }; // 期望报错但实际没有
补充说明:实际需求是要定义两种函数类型,其中Fn不允许返回Promise等异步包装类型,AsyncFn则明确返回Promise包裹的对象:
type Fn = () => Record<string, any>; // 期望不允许返回Promises、Observables等 type AsyncFn = () => Promise<Record<string, any>>; const foo: Fn = () => ({ 'ok': 'ok' }); // 期望正常工作 const foo2: Fn = () => { return Promise.resolve({ 'ok': 'ok' }) }; // 期望报错但实际没有
问题原因
原写法使用泛型条件类型时,TypeScript的类型推断逻辑会让T匹配返回值的实际类型。当返回Promise时,T被推断为Promise<{ok: string}>,此时条件类型返回never。但TypeScript允许任何返回值类型的函数赋值给返回never的函数类型(因为never是所有类型的子类型),所以不会触发预期的错误。
正确实现方式
通过条件类型直接约束函数的返回值,让被禁止的返回类型解析为never,利用TypeScript的赋值兼容性检查触发错误:
// 定义需要排除的返回类型集合 type ForbiddenTypes = Promise<any>; // 可添加 Observable<any> 等其他需要排除的类型 // 定义Fn类型:返回值必须是符合Record<string, any>且不属于禁止类型的类型 type Fn = () => Record<string, any> extends infer T ? T extends ForbiddenTypes ? never : T : never; type AsyncFn = () => Promise<Record<string, any>>; // 测试用例 const foo: Fn = () => ({ 'ok': 'ok' }); // ✅ 正常通过 const foo2: Fn = () => Promise.resolve({ 'ok': 'ok' }); // ❌ 报错:类型“Promise<{ ok: string; }>”不能赋值给类型“never”
也可以拆分出辅助类型让代码更清晰:
type ForbiddenTypes = Promise<any> | Observable<any>; type AllowedReturn<T> = T extends ForbiddenTypes ? never : T; type Fn = () => AllowedReturn<Record<string, any>>; type AsyncFn = () => Promise<Record<string, any>>;
这样实现后,只要函数返回ForbiddenTypes中包含的类型,就会触发类型错误,符合需求。
内容的提问来源于stack exchange,提问作者Matthieu Riegler
相关产品推荐
相关产品推荐

