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

如何在TypeScript中为秒和毫秒创建专属类型以避免混用?

TypeScript区分秒/毫秒参数的最佳实践

1. 品牌类型(Branded Types):编译时安全+零运行时开销

这是处理此类语义化数值类型的工业级最佳方案,通过给基本number类型添加唯一标识,让TypeScript在编译时区分不同语义的数值,运行时仍保留普通数字的性能。

// 定义带品牌标识的类型,确保秒和毫秒类型互斥
type Seconds = number & { readonly brand: unique symbol };
type Milliseconds = number & { readonly brand: unique symbol };

// 提供类型转换函数,明确生成对应语义的数值
const toSeconds = (value: number): Seconds => value as Seconds;
const toMilliseconds = (value: number): Milliseconds => value as Milliseconds;

// 目标函数,接收秒类型参数
function fn(foo: number, elapsedTime: Seconds) {
  // 业务逻辑中可直接当作number使用
  const elapsedMs = elapsedTime * 1000;
}

// 合法调用
fn(1234, toSeconds(3600)); // 编译通过

// 非法调用(编译报错)
fn(1234, 3600); // 错误:number类型无法赋值给Seconds
fn(1234, toMilliseconds(3600000)); // 错误:Milliseconds类型无法赋值给Seconds

核心逻辑:利用TypeScript结构类型系统的特性,unique symbol确保每个品牌类型唯一,编译器会拦截跨类型赋值,但运行时不会产生额外代码或性能损耗。

2. 字面量/枚举类型:适合固定参数场景

如果耗时参数只有固定的几个可选值,可直接用字面量类型或枚举限制输入:

// 限定允许传入的秒数值
type AllowedSeconds = 1 | 5 | 30 | 3600;

function fn(foo: number, elapsedTime: AllowedSeconds) {
  // ...
}

fn(1234, 3600); // 编译通过
fn(1234, 3600000); // 错误:3600000不在AllowedSeconds范围内

优点是简单直接,但灵活性差,无法支持任意合法的秒数值。

3. 类封装:带运行时校验

如果需要在运行时也保证参数的语义正确性,可通过类封装实现:

class Seconds {
  constructor(public value: number) {
    // 可选:添加运行时合法性校验
    if (value < 0) {
      throw new Error("秒数不能为负数");
    }
  }
}

function fn(foo: number, elapsedTime: Seconds) {
  console.log(elapsedTime.value);
}

fn(1234, new Seconds(3600)); // 编译通过
fn(1234, 3600); // 错误:number类型无法赋值给Seconds

缺点是会带来运行时开销,适合对参数合法性要求极高的场景。

方案优先级

优先选择品牌类型,它平衡了编译时类型安全、开发体验和运行时性能,是解决此类问题的标准实践。

内容的提问来源于stack exchange,提问作者Evgeniy Pozdnyakov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 14:45:59