I am new to typescript, and I am trying to define an enum-like class with some additional attributes. I have seen there are two different approaches of doing this:
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;
}
}
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?
Thanks,
Typescript supports lots of programming styles. To get a feel for the idioms that the AWS team chose for CDK, check out CDK github source. The lambda package source is a good place to start.
The CDK often uses static factory methods for configuration:
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:
// 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.
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
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.