aws / aws/jsii

String Enum values compile to the key rather than source value

Open
#4,276 3 comments 4 reactions 0 assignees View on GitHub
bug language/dotnet language/go language/java language/python language/ruby p1
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.