Typescript - 如何禁止两个解析为相同类型的类型别名互换使用?

Posted

技术标签:

【中文标题】Typescript - 如何禁止两个解析为相同类型的类型别名互换使用?【英文标题】:Typescript - How to disallow two type aliases that resolve to the same type to be used interchangeably? 【发布时间】:2020-08-20 12:10:34 【问题描述】:

假设我有两个或多个类型别名,例如:

declare type A = string;
declare type B = string;

我有这些类型的变量,以及对它们进行操作的函数。

const a1: A = "example of a";
const b1: B = "example of b";

function withA(a: A)
    console.log(a);


function withB(b: B)
    console.log(b);

我希望以下代码出错,但它不会:

withA(b1);
withB(a1);

我怎样才能做到这一点?我还需要能够使用字符串初始化变量(我假设使用强制转换)。但是,一旦初始化,我不希望这些类型是“隐式等效的”,并且希望编译器禁止它们的可互换使用。

我也不想使用类,如下所述: TypeScript - specific string types

【问题讨论】:

【参考方案1】:

顾名思义,类型别名不会向它们的别名类型添加任何内容。所以就 TS 而言,AB 是同一类型,即 string

您可以做的是使用品牌类型。这是一种技术,您采用基本类型(在本例中为string)并将其与具有属性的对象类型相交,以便从编译器的角度使该类型在结构上与其他任何东西不兼容。该属性不需要在运行时存在,它只是作为编译器的标记:

type A = string &  __brand: "A";
type B = string &  __brand: "B";

const a1: A = makeA("example of a");
const b1: B =  makeB("example of b");

function makeA(s: string) 
    return s as A

function makeB(s: string) 
    return s as B

function withA(a: A)
    console.log(a);


function withB(b: B)
    console.log(b);


withA(b1); // error
withB(a1); // error

实用函数makeAmakeB 不是绝对必要的,您可以在分配string 时使用类型断言,但它们会使DX 更好。

注意:在类型系统中形式化这种技术有两个提议(Structural tag type brands 和 Nominal unique type brands ),但在撰写本文时都没有合并,也许在未来的 TS 版本中我们将获得其中之一。

【讨论】:

感谢您的回答。我正在尝试将您描述为索引参数类型的品牌类型用于对象,但我很高兴:An index signature parameter type must be either 'string' or 'number'.ts(1023)。你知道我怎么能解决这个问题吗?我的财产看起来像这样:foos: Readonly< [key: A]: Foo >; @vasia 不可能,TS 要求索引是字符串或数字,甚至禁止string | number

以上是关于Typescript - 如何禁止两个解析为相同类型的类型别名互换使用?的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 应用程序中将 JSON 解析为 Typescript 类

如何提示 TypeScript 编译器两个泛型值必须相同?

如何告诉 TypeScript 两个泛型类型是相同的?

两个相互引用的类

TypeScript 类方法具有与构造函数相同的重载签名

模块解析:NPM 安装来自 Github 的 Typescript 包