TypeScript中如何让温度单位类型不兼容时触发警告?
用TypeScript品牌类型区分摄氏度与开尔文类型,实现类型安全检查
你当前的代码中,Celsius和Kelvin都是number的类型别名,TypeScript会将它们视为完全相同的类型,因此把Kelvin类型的值传给要求Celsius参数的toKelvin函数时,不会触发任何警告。要解决这个问题,需要借助TypeScript品牌类型(Branded Types),给不同的数值类型添加唯一标识,让编译器能识别它们的差异。
解决方案代码
// 用唯一符号作为品牌标识,避免类型冲突 const CELSIUS_BRAND = Symbol('celsius'); const KELVIN_BRAND = Symbol('kelvin'); // 定义品牌化的温度类型 type Celsius = number & { [CELSIUS_BRAND]: never }; type Kelvin = number & { [KELVIN_BRAND]: never }; const ABSOLUTE_ZERO = -273.15; // 创建类型安全的摄氏度值(可添加合法性校验) function createCelsius(value: number): Celsius { if (value < ABSOLUTE_ZERO) { throw new Error('摄氏度不能低于绝对零度'); } return value as Celsius; } // 创建类型安全的开尔文值(可添加合法性校验) function createKelvin(value: number): Kelvin { if (value < 0) { throw new Error('开尔文不能低于0'); } return value as Kelvin; } // 修改原函数,返回类型安全的Kelvin function f(): Kelvin { // 对应-220摄氏度的开尔文值:-220 - (-273.15) = 53.15 return createKelvin(53.15); } // toKelvin仅接受Celsius类型参数 function toKelvin(t: Celsius): Kelvin { return createKelvin(t - ABSOLUTE_ZERO); } // 错误场景:TypeScript会直接触发编译警告 toKelvin(f()); // 报错:类型“Kelvin”的参数不能赋给类型“Celsius”的参数
方案说明
- 品牌类型通过给
number交叉一个带有唯一符号属性的对象类型,让TypeScript在编译阶段区分Celsius和Kelvin,但运行时它们本质仍是普通number,不会产生额外性能开销。 createCelsius和createKelvin函数不仅用于生成类型安全的值,还可以加入业务校验逻辑,避免非法温度值流入代码。- 现在只要出现类型不匹配的传递(比如把
Kelvin传给要求Celsius的函数),TypeScript会立即在编译阶段抛出错误,完全符合你的需求。
如果不需要额外的合法性校验,也可以简化品牌类型的定义:
type Celsius = number & { __brand: 'celsius' }; type Kelvin = number & { __brand: 'kelvin' }; const createCelsius = (v: number) => v as Celsius; const createKelvin = (v: number) => v as Kelvin;
内容的提问来源于stack exchange,提问作者Jason Leaver
相关产品推荐
相关产品推荐

