繁体   English   中英

如何在 TypeScript 中定义不透明类型?

[英]How to define an opaque type in TypeScript?

如果我没记错的话,在 C++ 中你可以定义一个像这样的不透明类型......

class Foo;

...并像句柄一样使用它,例如在声明函数签名时...

void printFoo(const Foo& foo);

然后,应用程序代码可能会在没有看到 Foo 的实际定义的情况下使用对 Foo 的引用或对 Foo 的指针。

TypeScript 中是否有类似的东西——你会如何定义一个不透明的类型?

我的问题是,如果我定义这个......

interface Foo {};

...然后可以与其他类似类型自由互换。 有成语吗?

那是因为 TypeScript 类型系统是“结构化的”,因此任何具有相同形状的两种类型都可以相互分配——而不是“名义”,在这种情况下,引入像Foo这样的新名称将使其不可分配给相同的-shape Bar类型,反之亦然。

跟踪 TS 的名义类型添加是一个长期存在的问题

TS 中 opaque 类型的一种常见近似是使用唯一的标签来使任何两种类型在结构上不同:

// opaque type module:
export type EUR = { readonly _tag: 'EUR' };
export function eur(value: number): EUR {
  return value as any;
}
export function addEuros(a: EUR, b: EUR): EUR {
  return ((a as any) + (b as any)) as any;
}

// usage from other modules:
const result: EUR = addEuros(eur(1), eur(10)); // OK
const c = eur(1) + eur(10) // Error: Operator '+' cannot be applied to types 'EUR' and 'EUR'.

更好的是,标签可以用唯一的 Symbol 进行编码,以确保它永远不会被访问和使用:

declare const tag: unique symbol;
export type EUR = { readonly [tag]: 'EUR' };

请注意,这些表示在运行时没有任何影响,唯一的开销是调用eur构造函数。

newtype-ts提供了通用实用程序,用于定义和使用行为类似于我上面的示例的类型的值。

品牌类型

另一个典型用例是仅在一个方向上保持不可分配性,即处理可分配给numberEUR类型:

declare const a: EUR;
const b: number = a; // OK

这可以通过所谓的“品牌类型”获得:

declare const tag: unique symbol
export type EUR = number & { readonly [tag]: 'EUR' };

例如,在io-ts库中查看这种用法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM