google / google/jsinterop-generator

@JsEnum types cannot be used in a union

Open
#40 15 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
85
Forks
24
PR merge metrics
No merged PRs in 30d

Description

Steps to repro - use an externs file with an enum that is referenced by a union type. Roughly:

```
/**
* @enum {number}
*/
foo.bar.SomeEnum = {
ONE: 0,
TWO: 1,
THREE: 2,
FIVE: 3,
SEVEN: 4
};

/**
* @type {foo.bar.SomeEnum|string}
*/
foo.bar.ObjectWithProperties.prototype.thing;
```

The error is when j2cl tries to transpile the sources into js, it is reported that the union type is attempting an `instanceof` on the enum instead of just treating it like a number (which in this case is all it is).

Easy workaround: rewrite ObjectWithProperties.thing's type to be {number|string}, though that defeats the purpose a bit.

Proposed fix (not having given it great thought): The union type should instanceof based on the type label: in this case, `number`. This seems to be a bit difficult to implement though, since the original `@enum` might be already made into a java type? The `jsinterop.generator.model.Type` instances don't keep track of the type label at this time, so that would need to be added? It could potentially also be helpful in general, j2cl itself could implement `$isInstance` with this knowledge if it were part of the `@JsEnum` annotation?

Easier error reporting option: instead of waiting for j2cl to fail the generated java, something like this could throw when the generator is trying to emit the union's isFoo() method:

```diff --git a/java/jsinterop/generator/visitor/UnionTypeHelperTypeCreator.java b/java/jsinterop/generator/visitor/UnionTypeHelperTypeCreator.java
index b72a70a..c9d2e7b 100644
--- a/java/jsinterop/generator/visitor/UnionTypeHelperTypeCreator.java
+++ b/java/jsinterop/generator/visitor/UnionTypeHelperTypeCreator.java
@@ -262,6 +262,10 @@ public class UnionTypeHelperTypeCreator implements ModelVisitor {
return new ArrayTypeReference(OBJECT);
}

+ if (typeReference.getTypeDeclaration() != null && typeReference.getTypeDeclaration().isEnum()) {
+ throw new IllegalStateException("Can't use @enum in instanceof, so cannot construct union type");
+ }
+
// remove Type parameters
if (typeReference instanceof ParametrizedTypeReference) {
return ((ParametrizedTypeReference) typeReference).getMainType();
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.