TypeScript模板字面量映射类型:如何排除温度同单位转换?
解决TypeScript模板字面量映射类型中排除同单位转换的问题
你当前的类型定义问题在于,使用[U in ${T}to${T}]时,U是完整的转换键字符串(比如celsius_to_celsius),而非单独的温度单位。这时候用Exclude<T, U>根本不匹配类型,因为U是组合后的字符串,和T的单位类型不属于同一集合,所以无法排除同单位的情况。
正确的类型定义方案
利用TypeScript 4.1+支持的映射类型as子句,分别遍历源单位和目标单位,确保源单位与目标单位不同:
// 补全基础类型(如果未定义) type TemperatureUnit = 'celsius' | 'farenheit' | 'kelvin'; type ConversionCategoryType = 'temperature'; type ConversionItem<T> = { key: T }; // 修改后的ConversionsOptions类型 type ConversionsOptions<T extends string> = { key: ConversionCategoryType; items: Array<ConversionItem<T>>; formulas: { // 遍历每个源单位S,再为每个S生成排除自身后的目标单位D的转换键 [S in T as `${S}_to_${Exclude<T, S>}`]: (n: number) => number; }; };
验证效果
当你使用这个类型定义温度转换对象时:
const temperatureCategory: ConversionsOptions<TemperatureUnit> = { key: 'temperature', items: [ { key: 'celsius' }, { key: 'kelvin' }, { key: 'farenheit' }, ], formulas: { celsius_to_kelvin: (n) => n + 273.15, celsius_to_farenheit: (n) => n * (9 / 5) + 32, kelvin_to_farenheit: (n) => (n - 273.15) * (9 / 5) + 32, kelvin_to_celsius: (n) => n - 273.15, farenheit_to_kelvin: (n) => (n - 32) * (5 / 9) + 273.15, farenheit_to_celsius: (n) => (n - 32) * (5 / 9), }, };
- TypeScript会自动校验
formulas必须包含所有跨单位的转换键,不允许出现同单位的转换键(比如celsius_to_celsius会被类型检查报错)。 - 如果遗漏任何一个跨单位转换键,TypeScript也会提示类型不匹配,确保转换公式的完整性。
原理说明
这里的核心是拆分了源单位和目标单位的遍历逻辑:
- 先遍历每个源单位
S(比如celsius); - 对每个
S,用Exclude<T, S>排除自身,得到所有可转换的目标单位D; - 通过
as${S}to${D}``将源和目标单位组合成最终的转换键,从而精准生成所有跨单位的转换类型。
内容的提问来源于stack exchange,提问作者Louis Loiseau-Billon
相关产品推荐
相关产品推荐

