microsoft / microsoft/TypeScript
Proposal: Merge enum and const enum features
Personne n'a encore pris cette issue.
- Langage dominant
- Go
- Étoiles
- 111k
- Forks
- 14.3k
- Merge moyen
- 2 j 4 h
- PR mergées (30 j)
- 132
Description
Currently there are two enumerable types specified in TypeScript: enum and const enum.
Both of them aren't bijective, i.e. they both don't provide the ability to cast them arbitrarily and unambiguously between string, number and enum.
After discussing this on Gitter with @jsobell and @masaeedu I'd like to propose the following:
- merge both enumerable types into one: using
const enumon constant index expressions andenumon variable enum expressions. - always return a
numbervalue when astringindex expression is used on anenum. - allow for both,
numberandstringvalues, to be used as index argument types on the proposed mergedenumtype.
This would solve some major problems with the current design. Currently ...
enumvalues cannot be converted to theirnumberequivalent, only to theirstringrepresentation.const enumvalues cannot be converted to theirstringrepresentation, only to theirnumberequivalent.
(This blocksconst enumvalues from being used to serialize configuration settings into a commonly expected string value representation.)const enumvalues can not be converted toenumvalues and vice versa.
The key to providing the missing functionality is type inference. At compile time, TSC is able to tell whether a string or a number value is provided in an enum index argument. It's also able to tell whether the index expression is a constant or a variable.
Given these prerequisites the compiler can easily decide ...
- whether to use a
const enumvalue or anenumin the generated code, - whether to return the numerical value or string representation of the enum in the generated code.
(Variable index expressions of type any should be regarded as values of type string.This will result in maximum compatibility.)
So I'm proposing the following:
- Using a
stringindexer expression on anenumshall return anumberif the type of the L-value isn't the enum itself:enum[:string] => number. - Using a
stringindexer expression on anenumshall return anenumif the type of the L-value is the enum itself:enum[:string] => E. - Using a
numberindexer expression on anenumshall return astringif the type of the L-value isn't the enum itself:enum[:number] => string. - Using a
numberindexer expression on anenumshall return anenumif the type of the L-value is the enum itself:enum[:number] => E. - Using a
enumindexer expression on the sameenumtype shall return anumberif the type of the L-value isn't the enum itself:enum[:enum] => number. (During transpilation, this operation is practically redundant and may be cancelled from the output.) - Using a
enumindexer expression on the sameenumtype shall return anenumif the type of the L-value is the enum itself:enum[:enum] => E. (During transpilation, this operation is practically redundant and may be cancelled from the output.) - Using a constant
stringornumberindexer expression on anenumshall emit a constantnumbervalue in JavaScript (i.e., this is theconst enumequivalent). - Using a variable
stringornumberindexter expression on anenumshall emit an array indexer expression in JavaScript (i.e., this is theenumequivalent).
#### So, given the above prerequisites, here are two examples, hopefully shedding some light upon my proposal:
##### (A) Example illustrating type inference being used at compile time to decide whether to return a `number` or a `string` value from an enum:
The following TypeScript code:
// TypeScript
enum E {a, b, c}
const iN :number = 0, iS1 :string = "b", iS2 :string = "2";
// assigning to primitive types
const s :string = E[iN];
const n1 :number = E[iS1]; // special treatment because index type is string
const n2 :number = E[iS2]; // special treatment because index type is string
// assigning to enum
const es :E = E[iN];
const en1 :E = E[iS1]; // special treatment because index type is string
const en2 :E = E[iS2]; // special treatment because index type is string
... should result in the following JavaScript compilation result:
// JavaScript
var E;
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
E[E["c"] = 2] = "c";
E.toNumber = function (e)
{ return IsNaN(e) ? E[e] : E.isOwnProperty(e) ? +e : undefined; }
})(E || (E = {}));
var iN = 0, iS1 = "b", iS2 = "2";
var s = E[iN]; // === "a"
var n1 = E.toNumber(iS1); // === 1
var n2 = E.toNumber(iS1); // === 2
var es = E[iN] ? iN : undefined; // E[iN] returns a ?:string. --- result == 0
var en1 = E.toNumber(iS1); // == 1
var en2 = E.toNumber(iS1); // == 2
##### (B) Example illustrating `const enum` and `enum` being merged into one single type:
The following TypeScript code:
// TypeScript
enum E {a, b, c}
let e :E;
const n :number = 1;
const s :string ="c";
// constant assignments
e = E.a;
e = E[2];
e = E["a"];
// variable assignments
e = E[n];
e = E[E[n]];
e = E[s];
... should result in the following JavaScript compilation result:
// JavaScript
var E;
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
E[E["c"] = 2] = "c";
E.toNumber = function (e)
{ return IsNaN(e) ? E[e] : E.isOwnProperty(e) ? +e : undefined; }
})(E || (E = {}));
var e;
var n = 1;
var s = "c";
e = 0;
e = 2;
e = 0;
e = E[n] ? n : undefined; // E[n] returns a ?:string. --- result == 1
e = E[n] ? n : undefined; // The outer indexing operation is redundant and may be cancelled. --- result == 1
e = E.toNumber(s); // == 2
Some of the `E[n] ? n : undefined` constructs may be cancelled if runtime boundary checking isn't wanted/desired (new boolean compiler option?). So `e = E[n] ? n : undefined;` may then be transpiled to `e = n;`.
In the discussion on Gitter I learned about #3507, #592. Yet I feel the above proposal will add value to the ongoing discussion on improving the `enum` types.
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
L’issue mentionne TSC, l’indexation des enums, l’inférence de types et l’émission de JavaScript, mais ne précise ni fichiers ni tests. Commencez par examiner les issues associées #3507 et #592, puis suivez la vérification des enums et du JavaScript émis dans le compilateur. La tâche serait terminée lorsqu’un design convenu pour fusionner les comportements des enums aura été défini, avant de pouvoir cadrer l’implémentation.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- javascript, typescript
- Domaine
- compilers
- Type d'issue
- Fonctionnalité
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 18/100