Depuis que TypeScript a introduit les types d'unions, je me demande s'il n'y a aucune raison de déclarer un type enum. Considérez la déclaration de type enum suivante:
enum X { A, B, C }
var x:X = X.A;
et une déclaration de type d'union similaire:
type X: "A" | "B" | "C"
var x:X = "A";
S'ils servent essentiellement le même objectif et que les syndicats sont plus puissants et expressifs, pourquoi les énumérations sont-elles nécessaires?
Pour autant que je vois, ils ne sont pas redondants, pour la raison très simple que les types d'union sont purement un concept de temps de compilation alors que les énumérations sont réellement transpilées et se retrouvent dans le javascript résultant ( exemple ).
Cela vous permet de faire certaines choses avec des énumérations, qui sont autrement impossibles avec les types d'union (comme énumération des valeurs d'énumération possibles )
Il y a quelques raisons pour lesquelles vous voudrez peut-être utiliser un enum
enum
.enum
comme flags
. Indicateurs de bitsJe vois les grands avantages de l'utilisation d'une union, c'est qu'ils fournissent un moyen succinct de représenter une valeur avec plusieurs types et ils sont très lisibles. let x: number | string
EDIT: à partir de TypeScript 2.4, les énumérations prennent désormais en charge les chaînes.
enum Colors {
Red = "RED",
Green = "GREEN",
Blue = "BLUE",
}
Les énumérations peuvent être considérées conceptuellement comme un sous-ensemble de types d'union, dédié aux valeurs int
et/ou string
, avec quelques fonctionnalités supplémentaires mentionnées dans d'autres réponses qui les rendent conviviales à utiliser.
Mais les énumérations ne sont pas totalement sûres:
enum Colors { Red, Green, Blue }
const c: Colors = 100; // No errors!
type Color =
| 0 | 'Red'
| 1 | 'Green'
| 2 | 'Blue';
const c2: Color = 100; // Error: Type '100' is not assignable to type 'Color'
Les types d'union prennent en charge des données et des structures hétérogènes, permettant le polymorphisme par exemple:
class RGB {
constructor(
readonly r: number,
readonly g: number,
readonly b: number) { }
toHSL() {
return new HSL(0, 0, 0); // Fake formula
}
}
class HSL {
constructor(
readonly h: number,
readonly s: number,
readonly l: number) { }
lighten() {
return new HSL(this.h, this.s, this.l + 10);
}
}
function lightenColor(c: RGB | HSL) {
return (c instanceof RGB ? c.toHSL() : c).lighten();
}
Entre les énumérations et les types d'union, les singletons peuvent remplacer les énumérations. C'est plus verbeux mais aussi plus orienté objet :
class Color {
static readonly Red = new Color(1, 'Red', '#FF0000');
static readonly Green = new Color(2, 'Green', '#00FF00');
static readonly Blue = new Color(3, 'Blue', '#0000FF');
static readonly All: ReadonlyArray<Color> = [
Color.Red,
Color.Green,
Color.Blue,
]; // `[...] as readonly` to infer `ReadonlyArray<Color>` in TypeScript 3.4
private constructor(
readonly id: number,
readonly label: string,
readonly hex: string) { }
}
const c = Color.Red;
const colorIds = Color.All.map(x => x.id);
J'ai tendance à regarder F # pour voir les bonnes pratiques de modélisation. Une citation d'un article sur F # énumère sur F # pour le plaisir et le profit qui peut être utile ici:
En général, vous devriez préférer les types d'union discriminés aux énumérations, sauf si vous avez vraiment besoin d'avoir un
int
(ou unstring
) valeur qui leur est associée