最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Subtyping built-in types in Flow - Stack Overflow

programmeradmin2浏览0评论

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/

发布评论

评论列表(0)

  1. 暂无评论