-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace enums with string literals #324
Comments
What is the reason for this change? |
It makes things faster to use/hack on. It also still is fully type-checked if you're using TypeScript. For example, instead of: import { Button, Intent } from "@blueprintjs/core";
// later
<Button intent={Intent.DANGER}>Delete</Button> you could simplify to: import { Button } from "@blueprintjs/core";
// later
<Button intent="danger">Delete</Button> Of course, doing things the first way will still work as well, so no existing code should break. (Okay, it's possible some code could break depending on how enums were used in type positions or if people were doing crazy things with the numerical values of the enum...) |
These examples unfortunately aren't equal in terms of usability and speed. String operations are generally slower than enum (number) operations. You can't easily refactor a string literal, but you can for example hit F2 on an enum member and rename all occurrences, and more little things like this. Why not use these things for its intended use cases? |
the idea behind moving to typed string literals is that they can be used either as the performance effect of string vs number comparison is negligible; it's not useful to think like that. |
Here's a cool trick in ts2.1 (from https://basarat.gitbooks.io/typescript/docs/types/literal-types.html): /** Utility function to create a K:V from a list of strings */
function strEnum<T extends string>(o: Array<T>): {[K in T]: K} {
return o.reduce((res, key) => {
res[key] = key;
return res;
}, Object.create(null));
}
/**
* Sample create a string enum
*/
/** Create a K:V */
const Direction = strEnum([
'North',
'South',
'East',
'West'
])
/** Create a Type */
type Direction = keyof typeof Direction; |
https://github.com/dphilipson/typescript-string-enums could be ideal here |
This also makes the API nicer for vanilla Javascript devs, where enumeration types like this aren't as idiomatic as they are in Typescript. https://github.com/dphilipson/typescript-string-enums is handy (I use it), and Typescript is adding string enumerations as a first-class thing in 2.4 (microsoft/TypeScript#15486). Also, it makes it safer to use " |
TypeScript 2.4's string enums are now definitely the way to go. |
+1 for string enums: https://www.typescriptlang.org/docs/handbook/enums.html Make it a const enum to make it even lighter weight (no code emitted by typescript compiler; simply replaces all usages of the enums values with string literals during compile) export const enum RegionCardinality {
CELLS = "cells",
FULL_COLUMNS = "full-columns"
} (edit: On second thought, you may not want a const enum. A non-const enum will emit code that allows javascript projects to reference your enums by name. Const enums are more relevant for pure typescript projects) They are essentially interchangeable with string literal types, but have the benefit of being organized, providing a place to document each value, and providing more explicit code completion in IDEs. |
@UselessPickles ah didn't know about that |
@giladgray Yeah, the const enums will be more useful once this bug is fixed: microsoft/TypeScript#17372 |
Another thing worth being aware of is that string literals are NOT assignable to enum types, even if the string literal exactly matches one of the enum's values. By defining something as an enum, you are forcing all TypeScript users to use the enum instead of a string literal (not a bad thing, but worth being aware of). See this issue (marked "working as intended"): microsoft/TypeScript#15930 However, enum values ARE assignable to string literal types of matching values. Code examples: /**
* General concept of region cardinality described here.
* Individual values cannot be documented/explained clearly here.
*/
export type RegionCardinality = "cells" | "full-columns";
/**
* General concept of region cardinality described here.
*/
export enum RegionCardinalityEnum {
/**
* Documentation explaining CELLS cardinality
*/
CELLS = "cells",
/**
* Documentation explaining FULL_COLUMNS cardinality
*/
FULL_COLUMNS = "full-columns"
}
function acceptsStringLiteral(cardinality: RegionCardinality): void {}
function acceptsEnum(cardinality: RegionCardinalityEnum): void {}
acceptsStringLiteral("cells"); // valid
acceptsStringLiteral(RegionCardinalityEnum.CELLS); // valid
acceptsEnum("cells"); // COMPILER ERROR!!!
acceptsEnum(RegionCardinalityEnum.CELLS); // valid I personally don't see much value in string literal types now that string enums are available, though. My vote is for string enums only. |
@UselessPickles That's good, actually. If the enum changes, the strings wouldn't update. |
Tangentially related: I've been working on a little project to implement a generic visitor pattern that works on any string literal enum type, and any string literal union type. It provides a compile-time guarantee that you handle every possible value, including null/undefined when relevant. I just finished cleaning it up and documenting it last night. Check it out: https://github.com/UselessPickles/ts-string-visitor Available as an NPM package: https://www.npmjs.com/package/ts-string-visitor |
fixed by #1921 |
Let's replace enums with string literals. Instead of something like
we can have something like
@adidahiya pointed out that this may break existing apps so I'm adding this to the 2.x milestone for now. See #307 for existing PR. We can reopen it once we're ready to make this change.
List of enums:
The text was updated successfully, but these errors were encountered: