You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 12:50:53