如何用TypeScript断言对象仅包含字符串联合类型的属性?
实现方案
要确保对象仅包含字符串联合类型中定义的属性(可包含子集,禁止额外属性),可以通过以下两种方法实现:
方法1:使用辅助函数(推荐)
利用TypeScript的类型约束,通过辅助函数强制检查对象的键是否完全属于指定联合类型:
type SupportedChains = 'eth_mainnet' | 'eth_testnet'; // 定义允许的基础结构:联合类型中的键可选 type BaseFixtures = { [chain in SupportedChains]?: any }; // 辅助函数,约束传入对象只能包含SupportedChains中的键 const createFixtures = <T extends BaseFixtures & Record<Exclude<keyof T, SupportedChains>, never>>(obj: T) => obj; // 合法示例:仅包含允许的属性 const fixtures = createFixtures({ eth_testnet: { // ... }, }); // 非法示例:包含额外属性会触发报错 const invalidFixtures = createFixtures({ eth_testnet: { /* ... */ }, bsc_mainnet: { /* ... */ }, // TypeScript会提示该属性不允许 });
原理
Record<Exclude<keyof T, SupportedChains>, never> 会对超出联合类型的键进行约束:如果对象存在额外键,这些键的类型会被设为never,而对象属性无法赋值为never类型,从而触发错误。
方法2:使用严格类型断言
通过结合可选映射类型和never类型的索引签名,禁止额外属性:
type SupportedChains = 'eth_mainnet' | 'eth_testnet'; // 严格类型:允许联合类型中的键(可选),禁止任何额外字符串键 type StrictFixtures = { [chain in SupportedChains]?: any; } & { [key: string]: never; }; // 合法示例:仅包含允许的属性 const fixtures = { eth_testnet: { // ... }, } as StrictFixtures; // 非法示例:包含额外属性会触发断言报错 const invalidFixtures = { eth_testnet: { /* ... */ }, bsc_mainnet: { /* ... */ }, } as StrictFixtures;
原理
{ [key: string]: never } 会限制所有未在联合类型中定义的字符串键的值类型为never,一旦对象存在此类键,TypeScript会因类型不兼容报错。
关于你之前的尝试说明
- 使用
{ [chain: supportedChain]: any }报错:索引签名的参数类型只能是string、number、symbol,不能是字面量联合类型,因此TypeScript提示使用映射类型替代。 - 使用
{ [chain in supportedChain]: any }无法阻止多余属性:该映射类型默认要求所有联合类型的键必须存在(必填),且TypeScript的结构类型系统会忽略对象的额外属性(除非是直接赋值对象字面量的场景),同时你需要将其改为可选类型(添加?)才能允许仅包含子集属性,再结合额外约束才能禁止多余键。
内容的提问来源于stack exchange,提问作者YakovL
相关产品推荐
相关产品推荐

