TypeScript 5.0.2中const类型参数的这些问题是否符合预期?
TypeScript 5.0 const类型推断的场景疑问:预期限制还是Bug?
我对TypeScript 5.0的发布满怀期待,它本可以解决调用者在复杂函数参数类型中忘记添加as const的问题,但实际使用中发现该功能似乎存在Bug,或是不如预期强大。以下是两类场景,想确认这些是该功能的预期限制还是Bug?
1. 对象“校验器”类型
type NotEmpty<T extends Record<string, any>> = keyof T extends never ? never : T; const thing = <const O extends Record<string, any>>(o: NotEmpty<O>) => { return o; }; const t = thing({foo: ''}); // 推断类型为 { foo: string } ❌ // 但当在NotEmpty中添加映射类型时可正常工作 type NotEmptyMapped<T extends Record<string, any>> = keyof T extends never ? never : { [K in keyof T]: T[K] // ⬅️ 新增映射类型 }; const thingMapped = <const O extends Record<string, any>>(o: NotEmptyMapped<O>) => { return o; }; const tMapped = thingMapped({foo: ''}); // 推断类型为 { foo: "" } ✅
2. 条件要求或禁用对象键
type StringWithSpace = `${string} ${string}`; type FooBar<Foo extends string, Bar extends Record<string, string>> = { foo: Foo; } & ( Foo extends StringWithSpace ? { bar: Bar } : { bar?: never } ); // ⬇️ 使用const风格推断 declare function requireBarIfFooHasSpace<Foo extends string, const Bar extends Record<string, string>>(foobar: FooBar<Foo, Bar>): Bar; const foobar = requireBarIfFooHasSpace({ foo: 'has space', bar: { hello: 'world' } }); type inferredFooBar = typeof foobar; // ^? type inferredFooBar = {␊hello: string;␊} ❌
这看起来像是Bug,因为当FooBar为以下两种情况时,const风格推断可正常工作✅:
- 简化版:
type FooBar<Foo extends string, Bar extends Record<string, string>> = { foo: Foo; bar?: Bar; };
- 或将
Foo extends检查改为:
Foo extends string
若这些是预期行为,我暂未找到相关说明文档,如有疏漏敬请谅解。
补充编辑
- 第一个场景确实是Bug,相关讨论已确认。
- 第二个场景实际上符合预期,相关讨论中有解释原因。
- 针对第二个场景的一种解决方案:添加一个“占位”const类型参数,能让TS对交叉类型中的两个
bar属性版本都使用const风格推断。
type StringWithSpace = `${string} ${string}`; type FooBar<Foo extends string, Bar extends Record<string, string>, DummyBar extends undefined> = { foo: Foo; } & ( Foo extends StringWithSpace ? { bar: Bar } : { bar?: DummyBar } ); declare function requireBarIfFooHasSpace< Foo extends string, const Bar extends Record<string, string>, const DummyBar extends undefined ⬅️ 新增占位const参数 >(foobar: FooBar<Foo, Bar, DummyBar>): Bar; const foobar = requireBarIfFooHasSpace({ foo: 'has space', bar: { hello: 'world' } }); type inferredFooBar = typeof foobar; // ^? type inferredFooBar = {␊readonly hello: "world";␊}
内容的提问来源于stack exchange,提问作者Conor
相关产品推荐
相关产品推荐

