简体   繁体   English

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

[英]Enforcing a certain value using Type definition of Typescript

I have a Car class, which defines property for the model of the car. 我有一个Car类,它定义汽车model的属性。

There are just 3 models possible: 'ModelT', 'ModelQ' and 'ModelX'. 可能只有3种模型:“ ModelT”,“ ModelQ”和“ ModelX”。 So I have decided to define a Model type such as: 因此,我决定定义一个Model类型,例如:

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

and the Car constructor method as 和Car构造函数方法为

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

There is also a remote service which returns the type of car I should buy. 还有一个远程服务可以返回我应该购买的汽车类型。 If I use such service, my code looks like 如果我使用这种服务,我的代码看起来像

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

Which is the best way to enforce a logic to check at runtime that the model returned by the remote service is actually one of those specified in the type Model definition? 哪种方法是强制执行逻辑以在运行时检查远程服务返回的模型实际上是在type Model定义type Model指定的type Model之一的最佳方法?

It is not possible to start with a type/interface and get runtime behavior from it. 无法从类型/接口开始并从中获取运行时行为。 The type system in TypeScript exists only at the time you are writing the program. TypeScript中的类型系统仅在编写程序时存在。 It is completely erased from the emitted JavaScript that is executed at runtime. 它已从运行时执行的发出的JavaScript中完全删除

Luckily, you can do the reverse: start with an object that exists at runtime and get the TypeScript compiler to infer an analogous type for it. 幸运的是,您可以执行相反的操作:从运行时存在的对象开始,并获取TypeScript编译器为其推断类似类型。 In your case I'd suggest starting with an array of the values you want to check against, and proceed as described 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'

Now you have your Model type back again, and you also have the models array value you can use to create a type guard for it: 现在,您又恢复了Model类型,并且还拥有可以用来为其创建类型保护models数组值:

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

And now you can use it like this: 现在您可以像这样使用它:

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

Okay, hope that helps. 好的,希望对您有所帮助。 Good luck! 祝好运!

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

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