如何在TypeScript中提取品牌类型的底层类型?
TypeScript 通用提取品牌类型原始类型方案
问题场景
用TypeScript的交叉类型实现品牌类型时,提取背后的原始类型会遇到兼容性问题:
非字面量品牌可正常提取
如果品牌属性是宽泛的string类型,下面的类型工具能正确拿到原始类型:
type Branded = string & { brand: string; }; type Extract_I<T> = T extends infer V & { brand: string } ? V : never; type Result_I = Extract_I<Branded>; // 结果为 string
字面量品牌提取失效
但品牌属性是字面量(比如'brand')时,上面的工具就不好使了,会直接返回原品牌类型:
type LiteralBranded = string & { brand: 'brand'; }; type Result_II = Extract_I<LiteralBranded>; // 结果为 string & { brand: "brand" }
试过下面这种写法也没用:
type Extract_II<T> = T extends { brand: string } ? T & { brand: never } : never; // 不生效
解决办法
要搞定所有品牌类型(不管品牌是字面量还是宽泛类型),可以用下面两种通用方案:
方案一:利用条件类型推断
通过推断交叉类型中除了brand属性之外的部分:
type ExtractBrandBase<T> = T extends infer V & { brand: any } ? V : never;
方案二:用Omit移除品牌属性
直接通过Omit工具类型剔除brand属性,更直观:
type ExtractBrandBase<T> = Omit<T, 'brand'>;
测试效果
针对字面量品牌:
type LiteralBranded = string & { brand: 'brand' }; type Result_III = ExtractBrandBase<LiteralBranded>; // 结果为 string
针对非字面量品牌:
type Branded = string & { brand: string }; type Result_IV = ExtractBrandBase<Branded>; // 结果为 string
针对数字类型的品牌:
type UserId = number & { brand: 'userId' }; type Result_V = ExtractBrandBase<UserId>; // 结果为 number
内容的提问来源于stack exchange,提问作者Janek Eilts
相关产品推荐
相关产品推荐

