假设我正在编写处理UUID的代码。在内部,我想将它们表示为字符串。也就是说,每个UUID都是一个字符串,但不是每个字符串都是有效的UUID,并且我不想意外地将错误的东西分配给一个用于保存UUID的变量。所以我想创建一个类型' uuid'这样的分配就会失败:
let foo: uuid = "Some string"
但这应该成功:
function create_uuid(): uuid; { /* implementation? */ }
let foo: uuid = create_uuid();
let bar: string = uuid; // this is fine
有没有办法用Flow创建具有这些属性的类型?我在研究中发现$Subtype
,并认为这可行:
type uuid = $Subtype<string>;
但由于某种原因,它仍允许从字符串中进行分配。
答案 0 :(得分:6)
存在以下黑客攻击(缺点是UUID
也将是Object
):
// keep this constructor private
class IsUUID {}
export type UUID = string & IsUUID;
export function create(): UUID {
const uuid = 'blah' // <= your implementation
return ((uuid: any): UUID)
}
// tests
declare function f(uuid: UUID): void;
declare function g(s: string): void;
declare function h(o: Object): void;
let foo = create()
let bar: string = foo // <= ok
f(foo) // <= ok
f(bar) // <= error: string. This type is incompatible with IsUUID
g(foo) // <= ok
g(bar) // <= ok
h(foo) // <= ok :(
答案 1 :(得分:4)
编辑:这个答案已经过时了。自从提出这个问题以来,Flow已经实现了不透明类型。请参阅ESRogs&#39;答案。
可能有一些黑客可以解决这个问题,但你所要求的是opaque data type,而Flow目前不支持它们。以下是GitHub上Flow存储库中的some discussions。
答案 2 :(得分:2)
使用带有子类型约束的不透明类型。从文档中:
exports.js
export opaque type ID: string = string;
imports.js
import type {ID} from './exports';
function formatID(x: ID): string {
return "ID: " + x; // Ok! IDs are strings.
}
function toID(x: string): ID {
return x; // Error: strings are not IDs.
}