简体   繁体   English

使用Flow类型系统执行运行时检查?

[英]Enforcing run-time checks using the Flow type-system?

In my application, a UUID is just a string that conforms to a particular regex: 在我的应用程序中,UUID只是一个符合特定正则表达式的字符串:

'0b4ba6ba-496f-11e8-a21b-06f9c13aa914' // UUID

'hello world' // Not UUID

Now, I can check the format at run-time like this: 现在,我可以像这样在运行时检查格式:

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);
};

This is a run-time check, but I can leverage the type-system to ensure that the check is performed on all code paths. 这是一个运行时检查,但是我可以利用类型系统来确保对所有代码路径都执行检查。 Basically, I want to create a string-like type that is used to represent a string that has passed the isUuid check. 基本上,我想创建一个类似于字符串的类型,该类型用于表示已通过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

However, I want my existing code that takes UUIDs as strings to continue to work. 但是,我希望使用UUID作为字符串的现有代码继续工作。

Is this possible in Flow? Flow中有可能吗?

// @flow

type Uuid = string;

const ensureUuid = (x : string) : Uuid => {
  if (!isUuid(x)) {
    throw new TypeError(x + ' is not a Uuid');
  }

  return x;
};

This is possible using the opaque keyword: 使用opaque关键字可以实现:

Opaque type aliases are type aliases that do not allow access to their underlying type outside of the file in which they are defined. 不透明的类型别名是不允许在定义它们的文件之外访问其基础类型的类型别名。

Docs: https://flow.org/en/docs/types/opaque-types/ 文件: https//flow.org/en/docs/types/opaque-types/

You will need two files. 您将需要两个文件。

First uuid.js : 第一个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');
};

Then the consumer, index.js : 然后是消费者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);

With this setup, a Uuid instance can only be created via uuid.create . 使用此设置,只能通过uuid.create创建一个Uuid实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM