TypeScript如何通过排除特定字符串限制对象键名?
解决方案
1. 修复MutationRecord的键约束问题
你当前的MutationRecord定义无法禁止特定键,因为Exclude<string, "id" | "versionstamp" | "value">在TypeScript中仍然等价于string(string是所有字符串字面量的超集,排除有限几个值后还是string)。要真正禁止指定键,需要通过映射类型+never类型来实现:
type KvValue = string | number | boolean; type Mutation<T extends KvValue> = (value: T) => KvValue; // 定义禁止使用的键集合 type ForbiddenKeys = "id" | "versionstamp" | "value"; type MutationRecord<T extends KvValue> = { // 允许除禁止键外的所有字符串键,类型为Mutation<T> [K in Exclude<string, ForbiddenKeys>]: Mutation<T>; } & { // 禁止键的类型设为never,赋值时会触发类型错误 [K in ForbiddenKeys]: never; }; // 错误示例:赋值id会触发类型报错(类型'(n: number) => number'不能赋值给类型'never') const invalidRecord: MutationRecord<number> = { id: (n) => n * 2, }; // 正确示例 const validRecord: MutationRecord<number> = { increment: (n) => n + 1, multiply: (n) => n * 2, };
2. 交叉类型中保留禁止键的原类型
如果直接使用T & MutationRecord<T>,禁止键的类型会被never覆盖(因为T['id'] & never等于never)。要保留T中禁止键的原类型,需要通过Pick+Omit手动合并类型:
// 假设T是包含禁止键的类型 type ExampleT = { id: string; versionstamp: string; value: number; name: string; // 非禁止键 }; // 定义合并类型:保留T中的禁止键,其余键使用MutationRecord的类型 type CombinedType<T, U extends KvValue> = Pick<T, ForbiddenKeys> & Omit<MutationRecord<U>, ForbiddenKeys>; // 使用示例 const combined: CombinedType<ExampleT, number> = { id: "123", // 保留ExampleT中id的string类型 versionstamp: "v1", // 保留原类型 value: 456, // 保留原类型 increment: (n) => n + 1, // 非禁止键,类型为Mutation<number> };
简化版合并类型
如果不需要复用MutationRecord,也可以直接定义合并类型:
type CombinedType<T, U extends KvValue> = Pick<T, ForbiddenKeys> & { [K in Exclude<string, ForbiddenKeys>]: Mutation<U>; };
内容的提问来源于stack exchange,提问作者Noobster
相关产品推荐
相关产品推荐

