使用Typescript的Type定义强制执行某个值

时间:2019-03-17 12:59:15

标签: typescript typescript-types

我有一个Car类,它定义了汽车model的属性。

只有3种型号:'ModelT','ModelQ'和'ModelX'。因此,我决定定义一个Model类型,例如:

type Model = 'ModelT' | 'ModelQ' | 'ModelX';

和Car构造方法为

class Car {
  constructor(model: Model) {
    this.model = model;
  }
}

还有一个远程服务,可以返回我应该购买的汽车类型。如果我使用这种服务,我的代码看起来就像

const model = getModelFromRemoteService();
const car = new Car(model);

以下哪种方法是执行逻辑以在运行时检查远程服务返回的模型实际上是type Model定义中指定的模型之一的最佳方法?

1 个答案:

答案 0 :(得分:1)

不可能从类型/接口开始并从中获取运行时行为。 TypeScript中的类型系统仅在编写程序时存在。是completely erased来自运行时执行的发出的JavaScript。

幸运的是,您可以进行相反的操作:从运行时存在的对象开始,并获取TypeScript编译器为其推断类似类型。对于您的情况,建议您从要检查的值的数组开始,然后按照here所述进行操作:

// helper function needed before TS3.4 to get a tuple of string literals
// instead of just string[]
const stringTuple = <T extends string[]>(...args: T) => args;

const models = stringTuple('ModelT', 'ModelQ', 'ModelX');
// inferred type of models is ['ModelT', 'ModelQ', 'ModelX'];

// in TS3.4+, const models = ['ModelT', 'ModelQ', 'ModelX'] as const;

type Model = typeof models[number];
// inferred type of Model is 'ModelT' | 'ModelQ' | 'ModelX'

现在,再次返回您的Model类型,还拥有一个models数组值,可用于为其创建一个type guard

function isModel(x: any): x is Model {
  return models.indexOf(x) >= 0;
  // or return models.includes(x) for ES2016+
}

现在您可以像这样使用它:

class Car {
  model: Model;
  constructor(model: Model) {
    this.model = model;
  }
}
// assume this returns a string
declare function getModelFromRemoteService(): string;

// wrap getModelFromRemoteService so that it returns a Model 
// or throws a runtime error
function ensureModelFromRemoteService(): Model {
  const model = getModelFromRemoteService();
  if (isModel(model)) return model;
  throw new Error("THAT REMOTE SERVICE LIED TO ME");
}


const model = ensureModelFromRemoteService();
const car = new Car(model); // works now

好的,希望能有所帮助。祝你好运!