简体   繁体   English

Typescript 接口 + 常量与 class 用于定义类似枚举的 object

[英]Typescript interface + constants vs class for defining enum-like object

I am new to typescript, and I am trying to define an enum-like class with some additional attributes.我是 typescript 的新手,我正在尝试定义一个带有一些附加属性的类似枚举的 class。 I have seen there are two different approaches of doing this:我已经看到有两种不同的方法可以做到这一点:

  1. Using a class, similar to what I would do in Java:使用 class,类似于我在 Java 中所做的:
export class AwsRegion {
 
     public static US_EAST_1 = new AwsRegion('us-east-1');
     public static EU_WEST_1 = new AwsRegion('eu-west-1');
     public static US_WEST_2 = new AwsRegion('us-west-2');
 
     private name: string;
 
     constructor(name: string) {
         this.name = name;
     }
 
     public getName(): string {
         return this.name;
     }
 }

  1. Using interface + typescript constants:使用接口 + typescript 常量:
 export interface AwsRegion {
     readonly name: string;
 }

export const US_EAST_1: AwsRegion = { name: 'us-east-1' };
export const EU_WEST_1: AwsRegion = { name: 'eu-west-1' };
export const US_WEST_2: AwsRegion = { name: 'us-west-2' };

Is there any advantage to any of the two, or one that is more idiomatic in typescript than the other?两者中的任何一个有什么优势,或者在 typescript 中比另一个更惯用吗?

Thanks,谢谢,

Typescript supports lots of programming styles. Typescript 支持大量编程 styles。 To get a feel for the idioms that the AWS team chose for CDK, check out CDK github source .要了解 AWS 团队为 CDK 选择的习语,请查看CDK github 源代码 The lambda package source is a good place to start. lambda package源是一个很好的起点。

The CDK often uses static factory methods for configuration: CDK经常使用static工厂方法进行配置:

export class Runtime {
  // ...
  public static readonly NODEJS_14_X = new Runtime('nodejs14.x', RuntimeFamily.NODEJS, { supportsInlineCode: true });
  public static readonly PYTHON_2_7 = new Runtime('python2.7', RuntimeFamily.PYTHON, { supportsInlineCode: true });

Regarding your examples, note that as written, both approaches allow callers to create invalid configuration objects.关于您的示例,请注意,正如所写,这两种方法都允许调用者创建无效的配置对象。 Typescript will accept mars as a region without complaint: Typescript 将无怨无悔地接受mars作为区域:

// class
const mars: AwsRegion = new AwsRegion('mars');

// plain old object
const MARS_REGION: AwsRegion = { name: 'mars' };

You can fix this.你可以解决这个问题。 For the class approach: make the constructor private.对于 class 方法:将构造函数设为私有。

private constructor(name: string) {} 

// TS Error: Constructor of class 'AwsRegion' is private and only accessible within the class declaration
const mars: AwsRegion = new AwsRegion("mars")

For the POJO version, narrow the valid regions in the interface对于 POJO 版本,缩小界面中的有效区域

interface AwsRegion {
  readonly name: 'us-east-1' | 'eu-west-1' | 'us-west-2';
}

// TS Error:  Type '"mars"' is not assignable to type '"us-east-1" | "eu-west-1" | "us-west-2"'
const MARS_REGION: AwsRegion = { name: 'mars' };

Here is the TS Playground live code version of these examples.这是这些示例的 TS Playground 实时代码版本

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

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