TypeScript
TypeScript copied to clipboard
Enable constants as computed values for string enums
Search Terms
'TS18033', 'typescript define enum with constant string value', 'string enum computed constant'
Suggestion
Please consider enabling to use constant variables as values for string enums. The following code snippet fails compilation with TS18033 ('Only numeric enums can have computed members, but this expression has type 'string'. If you do not need exhaustiveness checks, consider using an object literal instead.')
const VALUE: string = 'ENUM_VALUE';
enum MyEnum {
KEY = VALUE, // <-- Fails with TS18033
}
console.log(MyEnum.KEY);
, whereas the following passes:
enum Values {
VALUE = 'ENUM_VALUE',
}
enum MyEnum {
KEY = Values.VALUE,
}
console.info(MyEnum.KEY);
Use Cases
Use string interpolation (templated strings) when defining the value of a string enum to be able to reuse pre-defined constants as part of the value. (E.g. namespace prefixes, extension postfixes)
Examples
const NAMESPACE: string = 'com.mycompany.myservice';
enum Errors {
INVALID_INPUT_ERROR = `${NAMESPACE}.errors#InvalidInput`,
}
Checklist
My suggestion meets these guidelines:
- [ X ] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [ X ] This wouldn't change the runtime behavior of existing JavaScript code
- [ X ] This could be implemented without emitting different JS based on the types of the expressions
- [ X ] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- [ X ] This feature would agree with the rest of TypeScript's Design Goals.
This would be a perfectly valid feature to implement since computed number values are already allowed.
Is there any reason why computed string values shouldn't be allowed for enums? Perhaps I'm not aware of something tied to the bigger picture?
@RyanCavanaugh can anybody from the TS team comment on my assumptions above? Thanks a lot.
I'm also curious about why computed enums are disabled for strings. Being able to use templated strings would be great. Looks like there was a similar issue here https://github.com/Microsoft/TypeScript/issues/20440.
This would be handy when when writing a React component with a prop that controls a css class. Right now I'm doing the following
enum ComponentVariant {
Foo,
Bar,
}
const classes = {
[ComponentVariant.Foo]: styles.fooClassName,
[ComponentVariant.Bar]: styles.barClassName,
}
export default function TheComponent({ variant }: {variant: ComponentVariant}) {
return <div className={classes[variant]} />
}
But it would be both cleaner, and also safer (i.e. prevent accidentally indexing into a non-existing value in the classes object) to do this directly:
enum ComponentVariant {
Foo = styles.fooClassName,
Bar = styles.barClassName,
}
export default function TheComponent({ variant }: {variant: ComponentVariant}) {
return <div className={variant} />
}
Following the namespace reasoning, highly useful for developing browser extensions or other scripts where we don't want to collision with pre-existing scripts, such as postMessage(<this value>, '*')
I also need this
Additionally symbols should be allowed to be used as enum values.
enum MyType {
foo = Symbol("foo"), // Error: ts(18033) - Only numeric enums can have computed members, but this expression has type 'symbol'. If you do not need exhaustiveness checks, consider using an object literal instead.
}
I'm with the same problem :/
please enable, thank you!
Facing the same issue. I would love to have computed values for strings so I can assign react components to enums.
PUSH!! i am currently facing this issue too. have an ENUM with endpoints and want to reuse pre-defined parts of that
export const customerEndpoint = '/customers';
export enum ENDPOINTS {
INVOICES = `${customers}/invoices`,
BASKET = `${customers}/basket`,
}
as an example
+1
I would love to have this on TS, thanks!
This would be a great feature, currently running into this same issue
I'm currently working to build a enum and interfaces in order to organize my database fields, finally as a custom orm system, and all my database fields have a prefix slot_
, that I wanted to specify into string literals in my enum:
// current enum
enum MyTableFields {
OBJECT_ID = 'slot_objectID',
CODE = 'slot_code',
LABEL = 'slot_label'
// ...and many other fields
}
// wanted enum
const slot_ = 'slot_'
enum MyTableFields {
OBJECT_ID = `${slot_}objectID`,
CODE = `${slot_}code`,
LABEL = `${slot_}label`
}
Apart from that this little formality, I wanted to explore another idea like handling schema or database table names inside enum, like this:
// current enum
enum MyTableFields {
OBJECT_ID = 'database_name.schema.slot_objectID',
CODE = 'database_name.schema.slot_code',
LABEL = 'database_name.schema.slot_label'
// ...and many other fields
}
// wanted enum
const path = `${databaseName}.${schema}.slot_`
enum MyTableFields {
OBJECT_ID = `${path}objectID`,
CODE = `${path}code`,
LABEL = `${path}label`
}
Enum with computed values could be helpfully helpful !
I too want to compute two enums with slight variations, such as a prefix.
+1 here, would be great innovation
+1 from me as well, I would like to assign values to enum variables depending on the environment via the ternary operator.
I support this as well, any prospects for implementation horizon?
+1, this would be quite helpful
There's another error message you might get if you try this:
Computed values are not permitted in an enum with string valued members. ts(2553)
I'm in favor if this change too. I would like to be able to do something like this:
This would be ideal! Especially when declaring API route constants.
import { getExact } from "../../util/env";
enum ApiRoutes {
users = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
blockUser = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
reverifyUser = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
resetPassword = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
preferences = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
pacemakers = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
matchPreferences = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
userLocation = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
tokens = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
messageThread = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
readMessage = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
suggestedSports = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
suggestedGenders = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
findMatch = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
likeUser = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
dislikeUser = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
createP2pReferralCode = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
p2pReferral = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
citiesAPI = 'https://wft-geo-db.p.rapidapi.com/v1/geo/cities',
discover = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
eventAttendance = `${getExact('REACT_NATIVE_BACKEND_URL')}/****`,
};
export default apiRoutes;
I also need this feature The deletion of this feature causes my code to be difficult to maintain
+1
With all due respect for the work that has been done for TypeScript so far. (Forgive me; English is not my mother tong)
I don't know if anyone gets the opposite impression somehow, but we TS lovers are not here for trolling. On the contrary, I personally would be willing to help for free.
Unfortunately, I personally have the impression that the ts-dev-team does what they want while ignoring the community's wishes and taking well-intentioned criticism and suggestions for improvement as an insult. Please be aware; that we are the community.
For example, this issue has been waiting for a solution almost for two years, and this is not an isolated case.
Although I want to help and I always try to be polite; (because I wish TS to continue and go in the right direction because I love using TS and I've put a lot of effort into it for years), I'm being terrorized and insulted by some core devs including dev-lead. I don't know how many I've had to block lately because of this. But that was not the case 2 years ago.
I do not know if it is because of the corona, but we must establish respectful communication again. (If someone can't contribute anything positive, at least he shouldn't hinder.)
TS-Team has to take community wishes seriously. They do what they want to do, block new ideas as off-topics, close bugs without solving them, and they want us to do what they want instead of doing what we need to do.
Sorry, I won't play this game for long. I convinced a giant company (German Railways) to use TS in the middleware, which was a three-digit million project. I probably wouldn't have done that if I had been a troll.
Dear TS team, please take this seriously.
Many thanks
+1
Meeting Notes https://github.com/microsoft/TypeScript/issues/49927 about this issue.
+1 also useful for enums utilizing i18n translations
export enum FooBarBas {
FOO = i18next.t('Foo'),
BAR = i18next.t('Bar'),
BAS = i18next.t('Bas'),
}
+1
+1