如何使用TypeScript泛型限制对象的合法键名规则
如何在TypeScript中强制对象键名符合以$开头且仅含字母的规则?
通过映射类型结合你已有的DFA验证逻辑,就能实现对对象键名的强制约束。核心思路是利用TypeScript的条件类型,只保留那些通过DFA验证的键名作为合法索引。
完整实现代码
interface Test { testProperty: string; } // 保留你已有的DFA相关类型定义 type Head<StrT extends string> = StrT extends `${infer HeadT}${string}` ? HeadT : never; type Tail<StrT extends string> = StrT extends `${string}${infer TailT}` ? TailT : never; interface Dfa { startState: string; acceptStates: string; transitions: Record<string, Record<string, string>>; } type AcceptsImpl<DfaT extends Dfa, StateT extends string, InputT extends string> = InputT extends '' ? StateT extends DfaT['acceptStates'] ? true : false : AcceptsImpl<DfaT, DfaT['transitions'][StateT][Head<InputT>], Tail<InputT>>; type Accepts<DfaT extends Dfa, InputT extends string> = AcceptsImpl< DfaT, DfaT['startState'], InputT >; interface MyDfa { startState: '0'; acceptStates: '1'; transitions: { '0': Record<'$', '1'> & Record<string, 'fail'>; '1': Record< | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z', '1' > & Record<string, 'fail'>; fail: Record<string, 'fail'>; }; } type ValidObjectKey<T extends string> = Accepts<MyDfa, T>; // 核心修改:用映射类型筛选合法键名 type TestObject = { [K in string as ValidObjectKey<K> extends true ? K : never]: Test; }; // 合法示例:无编译错误 const validTestObject: TestObject = { $prop1: { testProperty: 'test' }, $validKey: { testProperty: 'valid' }, }; // 非法示例:会触发编译错误(取消注释可验证) // const invalidTestObject: TestObject = { // propWithoutDollar: { testProperty: 'invalid' }, // 缺少$前缀 // $keyWithNum123: { testProperty: 'invalid' }, // 包含数字字符 // };
实现说明
- 映射类型中的
as子句是关键:它会遍历所有字符串类型的键名K,仅保留ValidObjectKey<K>返回true的键,其余键会被排除。 - 当你尝试添加不符合规则的键时,TypeScript会直接抛出编译错误,从类型层面强制约束键名格式。
简化替代方案(无需DFA)
如果觉得DFA写法太繁琐,也可以用TypeScript的模板字符串类型直接实现约束,代码更简洁:
interface Test { testProperty: string; } // 直接定义合法键名:以$开头,后续仅包含大小写字母 type ValidKey = `$${Capitalize<string> | Lowercase<string>}`; type TestObject = { [K in ValidKey]: Test; };
内容的提问来源于stack exchange,提问作者msbb
相关产品推荐
相关产品推荐

