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

如何实现允许基类赋值但禁止同基类其他标称类型赋值的LooseNominal类型?

实现允许基类型赋值但禁止同基类型其他标称类型赋值的LooseNominal

我需要创建一种“松散”标称类型LooseNominal,它允许从基类型直接赋值,但禁止从拥有同一基类型的其他标称类型赋值。现有一个严格标称类型的实现:

declare const nominalSymbol: unique symbol;
export type Nominal<T extends string, U> = U & { [nominalSymbol]: T };

我尝试过将LooseNominal定义为Nominal<T, U> | U,但这样会导致不同的LooseNominal类型之间因为共享基类型而可以互相赋值,不符合需求。期望的行为如下:

type Address = LooseNominal<'Address', string>;
type FirstName = LooseNominal<'FirstName', string>;

let address: Address = "123 Some St";
let firstName: FirstName = "John";
address = "456 Another St"; // 无问题
address = firstName; // 期望触发类型错误!

解决方案

可以利用可选的唯一符号属性来实现需求。核心思路是让LooseNominal类型包含基类型,同时附加一个可选的符号属性用于区分不同的标称类型。普通基类型值因为没有这个属性可以直接赋值,而其他标称类型因为带有属性值不匹配的符号属性会被TypeScript拦截。

实现代码如下:

declare const nominalSymbol: unique symbol;

// 保留原有的严格标称类型
export type Nominal<T extends string, U> = U & { [nominalSymbol]: T };

// 实现松散标称类型
export type LooseNominal<T extends string, U> = U & { [nominalSymbol]?: T };

测试验证

type Address = LooseNominal<'Address', string>;
type FirstName = LooseNominal<'FirstName', string>;

let address: Address = "123 Some St"; // ✅ 正常赋值
let firstName: FirstName = "John"; // ✅ 正常赋值

address = "456 Another St"; // ✅ 基类型值可正常赋值
address = firstName; // ❌ 类型错误:类型"FirstName"不能赋值给类型"Address",属性"[nominalSymbol]"的类型不兼容

原理说明

  • 普通的基类型值(如string)没有nominalSymbol属性,而LooseNominal中的该属性是可选的,因此可以直接赋值。
  • 不同的LooseNominal类型带有不同的符号属性值('Address' vs 'FirstName'),当互相赋值时,TypeScript会检查属性类型的兼容性,因为属性值不匹配而触发类型错误。
  • 如果需要将严格的Nominal类型赋值给对应的LooseNominal类型,也是可行的,因为Nominal<T, U>是LooseNominal<T, U>的子类型(必填属性是可选属性的子类型)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:56:18