You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

若这些是预期行为,我暂未找到相关说明文档,如有疏漏敬请谅解。


补充编辑

  1. 第一个场景确实是Bug,相关讨论已确认。
  2. 第二个场景实际上符合预期,相关讨论中有解释原因。
  3. 针对第二个场景的一种解决方案:添加一个“占位”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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 17:47:48