在我的应用程序中,UUID只是一个符合特定正则表达式的字符串:
'0b4ba6ba-496f-11e8-a21b-06f9c13aa914' // UUID
'hello world' // Not UUID
现在,我可以像这样在运行时检查格式:
const isUuid = (x : string) : boolean => {
const pattern = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
return pattern.test(x);
};
这是一个运行时检查,但是我可以利用类型系统来确保对所有代码路径执行检查。基本上,我想创建一个类似字符串的类型,用于表示已通过isUuid
检查的字符串。
type Uuid = ?
let s : string = '0b4ba6ba-496f-11e8-a21b-06f9c13aa914';
let x : Uuid = s; // Type error
let y : Uuid = ensureUuid(s); // Type checked, but may throw at run-time
但是,我希望以UUIDs作为字符串的现有代码能够继续工作。
在Flow中有可能吗?
// @flow
type Uuid = string;
const ensureUuid = (x : string) : Uuid => {
if (!isUuid(x)) {
throw new TypeError(x + ' is not a Uuid');
}
return x;
};
答案 0 :(得分:1)
可以使用opaque
关键字:
不透明类型别名是不允许在定义它们的文件之外访问其基础类型的类型别名。
文档:https://flow.org/en/docs/types/opaque-types/
您将需要两个文件。
第一个uuid.js
:
// @flow
export opaque type Uuid = string;
export const is = (x : string) : boolean => {
const pattern = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
return pattern.test(x);
};
export const create = (x : string) : Uuid => {
if (is(x)) {
return x;
}
throw new TypeError('"' + x + '" is not a valid UUID');
};
然后,消费者index.js
:
// @flow
import * as uuid from './uuid';
import type { Uuid } from './uuid';
const s : string = '0b4ba6ba-496f-11e8-a21b-06f9c13aa914';
// const q : Uuid = s; // Type error!
const r : Uuid = uuid.create(s); // Type checked, but might throw a run-time error
// const h : Uuid = 'not allowed!';
// const i : Uuid = ('not allowed!' : Uuid);
使用此设置,只能通过Uuid
创建一个uuid.create
实例。