typescript - 如何在 TypeScript 中定义不透明类型?
问题描述
如果我没记错的话,在 C++ 中你可以定义一个像这样的不透明类型......
class Foo;
...并像句柄一样使用它,例如在声明函数签名时...
void printFoo(const Foo& foo);
然后,应用程序代码可能会使用对 Foo 的引用或指向 Foo 的指针,而不会看到 Foo 的实际定义。
TypeScript 中是否有类似的东西——你将如何定义不透明类型?
我的问题是,如果我定义这个......
interface Foo {};
...然后可以与其他类似类型自由互换。有成语吗?
解决方案
那是因为 TypeScript 类型系统是“结构化的”,所以任何两种具有相同形状的类型都可以相互分配一个 - 而不是“名义”,其中引入一个新名称Foo
会使其无法分配给相同的 -形状Bar
类型,反之亦然。
跟踪 TS 的名义类型添加存在这个长期存在的问题。
TS 中不透明类型的一种常见近似是使用唯一标签来使任何两种类型在结构上有所不同:
// 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提供了通用实用程序,用于定义和使用与我上面的示例类似的类型的值。
品牌类型
另一个典型用例是仅在一个方向上保持不可分配性,即处理EUR
可分配给的类型number
:
declare const a: EUR;
const b: number = a; // OK
这可以通过所谓的“品牌类型”获得:
declare const tag: unique symbol
export type EUR = number & { readonly [tag]: 'EUR' };
例如,参见图书馆中的这种用法。io-ts
推荐阅读
- amazon-web-services - AWS API 网关集成和 Terraform
- vb.net - 我在同一个表单上有多个面板,我想在两个面板之间传递一个值
- python - 如何在前台运行烧瓶自定义 cli 命令?
- emacs - emacs elisp 为什么变量不能在这里工作?
- git - 正确的 git 工作流程,允许我在不提交的情况下查看以前的版本
- performance - 使用矢量化通过反向乘法加速 matlab 代码
- swift - Swift:WKWebView 中 UIRefreshControl 的自定义操作
- format - IEEE-754 标准
- java - 将组件从表应用到另一个表
- google-sheets - 通过删除空格和使用标题来汇总行数据(Google 表格)