In TypeScript 1.8, they added a new type called a "string literal type" which lets you declare a type that can only be one of a set of finite values. The example that they give is:
type Easing = "ease-in" | "ease-out" | "ease-in-out";
But, in all their examples, the type is either defined outside of the class that it is used in or defined inline without an alias. As explained (fairly tersely) in the answers to this question, type alias declarations are scoped to their containing module.
In my project, I would like to define type aliases for string literals that are paired with specific classes and used in multiple places. Because of the structure of the APIs that I am consuming, there are multiple classes which each have properties of the same name but different potential values. I'd like to keep my code neat and not have a bunch of global type declarations with prefixes (MyClassAPropertyValue
, MyClassBPropertyValue
, etc.) if I can help it.
So, is there any way to declare a type
within class scope (preferably so that it is consumable from external modules)? If not, is there a close substitute or planned feature that will fill this use case?
Use case:
Suppose I have two classes that wrap my underlying API data. Each class represents different data, they just happen to have some properties with the same name. I want a way of defining properties like so:
export class APIObjectA {
// Valid values in APIObjectA
public type Property1Value = "possible_value_A" | "possible_value_B";
public type Property2Value = "possible_value_C" | "possible_value_D";
// Here, "Property1Value" refers to the version in APIObjectA
public get property1(): Property1Value {
// Return value of property1 from underlying API data
}
public get property2(): Property2Value {
// ...
}
}
export class APIObjectB {
// Valid values in APIObjectB
public type Property1Value = "possible_value_E" | "possible_value_F";
public type Property2Value = "possible_value_G" | "possible_value_H";
// In this context, "Property1Value" refers to the version in APIObjectB
public get property1(): Property1Value {
// ...
}
public get property2(): Property2Value {
// ...
}
}
And then, ideally, I'd be able to refer to a specific type in consuming code so that I have types everywhere:
var myNewValue: APIObjectB.Property1Value = "possible_value_F";
You can't define types (whether they be nested classes, enums or string literal types) directly inside a class.
But, as shown in this answer, you can get around this by defining the nested type in a module of the same name.
export class APIObjectA {
// Here, "Property1Value" refers to the version in APIObjectA
public get property1(): APIObjectA.Property1Value {
// Return value of property1 from underlying API data
}
public get property2(): APIObjectA.Property2Value {
// ...
}
}
module APIObjectA {
// Valid values in APIObjectA
export type Property1Value = "possible_value_A" | "possible_value_B";
export type Property2Value = "possible_value_C" | "possible_value_D";
}
export class APIObjectB {
// In this context, "Property1Value" refers to the version in APIObjectB
public get property1(): APIObjectB.Property1Value {
// ...
}
public get property2(): APIObjectB.Property2Value {
// ...
}
}
module APIObjectB {
// Valid values in APIObjectB
export type Property1Value = "possible_value_E" | "possible_value_F";
export type Property2Value = "possible_value_G" | "possible_value_H";
}
Note that you will need to use the fully qualified name for the return types of your properties. For example, you need to use APIObjectB.Property1Value
instead of just Property1Value
.