admin管理员组

文章数量:1332339

Suppose I'm writing code that handles UUIDs. Internally, I want to represent them as strings. That is, every UUID is a string, but not every string is a valid UUID, and I don't want to accidentally assign the wrong thing to a variable meant to hold a UUID. So I want to create a type 'uuid' such that this assignment would fail:

let foo: uuid = "Some string"

But this should succeed:

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

Is there any way to create a type with Flow that has these properties? I found $Subtype in my research, and thought this might work:

type uuid = $Subtype<string>;

But for some reason it still allows assignment from a string.

Suppose I'm writing code that handles UUIDs. Internally, I want to represent them as strings. That is, every UUID is a string, but not every string is a valid UUID, and I don't want to accidentally assign the wrong thing to a variable meant to hold a UUID. So I want to create a type 'uuid' such that this assignment would fail:

let foo: uuid = "Some string"

But this should succeed:

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

Is there any way to create a type with Flow that has these properties? I found $Subtype in my research, and thought this might work:

type uuid = $Subtype<string>;

But for some reason it still allows assignment from a string.

Share Improve this question asked Nov 12, 2016 at 1:52 JoshJosh 2,0893 gold badges20 silver badges30 bronze badges 1
  • AFAIK, flow can not define some specific subtype of a string. e.g. it can never differentiate between "Some String" and "uuid chars". They are equivalent subtypes of a string. – Red Mercury Commented Nov 12, 2016 at 3:19
Add a ment  | 

3 Answers 3

Reset to default 6

There is the following hack (the downside is that a UUID will be also an 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 inpatible with IsUUID
g(foo) // <= ok
g(bar) // <= ok
h(foo) // <= ok :(

Edit: This answer is out of date. Flow has implemented opaque types since this question was asked. Refer to ESRogs' answer.

There may be some hacks that can solve this problem, but what you are asking for is known as an opaque data type and Flow does not currently support them. Here are some discussions of them on the Flow repository on GitHub.

Use an opaque type with a subtyping constraint. From the docs:

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.
}

https://flow/en/docs/types/opaque-types/

本文标签: javascriptSubtyping builtin types in FlowStack Overflow