String Enum values compile to the key rather than source value
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 267
- Avg merge
- 1d 25m
- Merged PRs (30d)
- 14
Description
### Describe the bug
In typescript, we can represent string enums like so:
```typescript
export enum EnvironmentName {
DEV = 'dev',
QA = 'qa',
FOO = 'bar'
}
```
However, in all languages besides js, jsii compiles these so that the key name is used. For instance, python output looks like:
```python
@jsii.enum(jsii_type="@example/my-package.EnvironmentName")
class EnvironmentName(enum.Enum):
DEV = "DEV"
QA = "QA"
FOO = "FOO"
```
When using the enum as a type, this doesn't matter, as the literal value is unimportant. But when outputting a string, Python developers are now outputting `FOO` whereas TS/JS users of the same construct output `bar`. This breaks interoperability.
### Expected Behavior
The string representation of an enum value in all languages should match the source code. As noted in the [jsii design tenants](https://aws.github.io/jsii/specification/1-introduction/#design-tenets-unless-you-know-better-ones):
> - jsii applications behave identically regardless of the language they are written in. It favors correctness over performance.
> - Unsupported idioms will cause a compile-time error to be emitted.
> - When prohibiting an idiom, jsii strives to provide an error message that gives the user insight into why the pattern cannot be supported.
Applications should behave identically, and if that is not possible, there should be a compiler error for string enums where the key and value do not match.
### Current Behavior
An application which uses runtime validation of enum values will fail in languages other than JS. For instance:
```typescript
export const validateEnv = (env: EnvironmentName) => {
if (Object.values(EnvironmentName).includes(env)) {
throw new TypeError(`Value "${env}" is not a valid environment name.`);
}
}
```
I believe this is because the JS assembly is used when calling `Object.values()`, and the value passed in doesn't match JS values due to the serialization differences.
### Reproduction Steps
1. Create a construct library which uses a string enum's values inside functional code.
2. Publish package to NPM and another supported target.
3. Import the package in the target language and call the function.
4. Observe output.
### Possible Solution
Rework how JSII models string enum values. Not sure how complicated this is, but it seems important for correctness.
### Additional Information/Context
_No response_
### SDK version used
jsii=5.2.8; jsii-pacmak=1.89.0
### Environment details (OS name and version, etc.)
MacOS 11.7.10
Contributor guide
Research direction
Start by reproducing the string enum in TypeScript, then compare the jsii assembly and generated Python output with the source values. Done means all supported languages preserve the source string value, or the compiler rejects string enums whose keys and values differ.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100