如何定义Shape<RootType>类型:键对应值需满足特定约束?
解决方案
要实现满足需求的Shape<RootType>泛型类型,我们可以通过交叉类型结合Partial、Record和Exclude来分别约束RootType的键和额外键的值类型:
type Shape<RootType> = // 允许可选地指定RootType的键,对应值只能为"A" Partial<Record<keyof RootType, "A">> & // 允许可选地指定任意非RootType的键,对应值只能为"B"或"C" Partial<Record<Exclude<string | number | symbol, keyof RootType>, "B" | "C">>;
方案解释
Partial<Record<keyof RootType, "A">>:Record<keyof RootType, "A">定义了RootType所有键必须对应值"A"的类型Partial让这些键变为可选,允许只指定部分RootType的键
Partial<Record<Exclude<string | number | symbol, keyof RootType>, "B" | "C">>:Exclude<string | number | symbol, keyof RootType>筛选出所有不属于RootType的键(覆盖字符串、数字、符号类型的键)Record约束这些额外键的值只能是"B"或"C"Partial让这些额外键也变为可选,支持任意数量的额外键
验证测试用例
使用你提供的User类型和test函数:
type User = { id: number; name: string; unused: number; } declare function test<T extends Shape<User>>(): void; // ✅ 编译通过:符合所有约束 test<{ id: "A", name: "A", something: "B", else: "C", }>(); // ❌ 编译失败:`id`是User的键,值只能为"A" test<{ id: "B" }>(); // ❌ 编译失败:`name`是User的键,值只能为"A" test<{ name: 123 }>(); // ❌ 编译失败:额外键的值只能为"B"或"C" test<{ something: "A" }>();
原方案问题分析
你之前的写法存在两个核心错误:
- 索引签名仅限定了
symbol类型的键,忽略了常见的string和number类型键,导致无法约束大部分场景 - 条件判断
KeyType extends RootType逻辑错误,应该判断键是否属于RootType的键集合(即KeyType extends keyof RootType),而非键类型是否继承自RootType本身
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

