React TypeScript:如何约束泛型参数同时保留keyof T类型
解决方案:约束泛型同时保留具体键类型
嘿,这个问题其实挺典型的——既要给泛型加结构约束,又不想丢失具体的类型推断细节。别担心,只需要给泛型参数A加上合适的约束,同时让TypeScript保持对具体键的推断就行,看下面的实现:
// 给ComponentProps的泛型A添加约束:必须是键为string、值为string的对象 interface ComponentProps<A extends Record<string, string>> { actions: A; onAction(key: keyof A): void; } // 组件定义同样给泛型A加上相同约束 function Component<A extends Record<string, string>>(props: ComponentProps<A>) { return <div>{/* ... */}</div>; } // 使用示例,完全符合你的需求 <Component actions={{ a: 'one', b: 'two' }} onAction={action => { // 这里action的类型依然是"a" | "b",没有退化为string! console.log(`触发了动作:${action}`); }} />;
为什么这能生效?
这里的Record<string, string>和你写的{[key: string]: string}是等价的,它给A设定了结构规则:只能是键为字符串、值为字符串的对象。但关键在于,TypeScript并不会因为这个约束就把A的类型拓宽成宽泛的Record<string, string>——它依然会根据你传入的actions对象,推断出具体的类型(比如{a: string, b: string})。这样一来,keyof A自然就是该对象所有键的联合类型("a" | "b"),完全满足你的要求。
如果有时候你遇到类型意外退化为string的情况,大概率是因为TypeScript的自动类型拓宽(比如当actions被定义为一个单独的变量而不是直接传入组件时),这时候可以给actions加上as const断言来强制保留字面量类型,但在上面的直接传入场景下,完全不需要额外操作。
内容的提问来源于stack exchange,提问作者Rico Kahler
相关产品推荐
相关产品推荐

