2016-11-12 30 views
3

假设我正在编写处理UUID的代码。在内部,我想将它们表示为字符串。也就是说,每个UUID都是一个字符串,但并不是每个字符串都是一个有效的UUID,我不希望将错误的事情分配给一个用来保存UUID的变量。所以,我想创建一个类型“UUID”,使得这项任务会失败:Flow中的子类型内置类型

let foo: uuid = "Some string" 

但是,这应该会成功:

function create_uuid(): uuid; { /* implementation? */ } 
let foo: uuid = create_uuid(); 
let bar: string = uuid; // this is fine 

有什么方法来创建流类型具有这些特性?我在我的研究中发现$Subtype,并认为这可能工作:

type uuid = $Subtype<string>; 

但由于某些原因,它仍然允许从一个字符串赋值。

+0

AFAIK,流程无法定义一些字符串的特定子类型。例如它永远不能区分“一些字符串”和“uuid字符”。它们是字符串的等同子类型。 –

回答

5

有下面的技巧(不足之处是一个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

我只是想为某些情况添加另一种可能的解决方案:'export class UUID extends String {}'。字符串对象与字符串不完全相同,但在很多其他方面像字符串一样 - 例如,JSON.Stringify()会将其字符串化为字符串而不是对象。 – Josh

3

可能有一些黑客可以解决这个问题,但你要求的是被称为一个opaque data type和Flow目前不支持它们。以下是他们在GitHub上的Flow存储库中的somediscussions