TypeScript中Exclude<string, 'set'>被简化为string的原因及实现方案
底层逻辑说明
Exclude<T, U>是针对联合类型设计的工具类型,仅当T是联合类型时才会触发分布式条件判断,逐个排除匹配U的联合成员。
而string是基础基元类型,不是由有限个字符串字面量组成的联合,TS不可能枚举所有可能的字符串值来剔除'set',因此Exclude<string, 'set'>运算后会直接简化回string类型。这就导致你定义的索引签名覆盖了所有string键(包括set),后续交叉的set函数类型和索引签名要求的string类型冲突,最终set属性会被推导为never,完全不符合预期。
可行实现方案
方案1:键重映射(TS 4.1+ 推荐)
利用TS 4.1引入的映射类型键重映射语法,直接过滤掉特殊属性名,不会和索引签名冲突:
type Attributes = { readonly [key in string as key extends 'set' ? never : key]: string } & { readonly set: (attr: string, value: string) => void }
如果有多个特殊属性需要单独定义,只需要扩展过滤逻辑即可:
// 示例:新增delete特殊方法 type Attributes = { readonly [key in string as key extends 'set' | 'delete' ? never : key]: string } & { readonly set: (attr: string, value: string) => void readonly delete: (attr: string) => void }
方案2:低版本TS兼容写法
如果需要支持4.1以下的TS版本,可以用联合类型作为索引签名的值类型,缺点是普通属性访问时会携带方法类型的联合,需要自行收窄:
interface Attributes { readonly set: (attr: string, value: string) => void readonly [key: string]: string | ((attr: string, value: string) => void) }
内容的提问来源于stack exchange,提问作者Bálint Réthy
相关产品推荐
相关产品推荐

