Skip to content

Allow never in discriminated union members instead of throwing a spec-generation error #1482

Description

@amine-by

Feature Request/Enhancement

Nitrogen currently fails to generate a spec when a TypeScript type contains never, with:

❌  Failed to generate spec for Entity! Error: The TypeScript type "never" cannot be resolved - is it imported properly? Make sure to import it properly using fully specified relative or absolute imports, no aliases.
❌  No specs found in Entity.nitro.ts!

This makes it impossible to use the standard TypeScript pattern for discriminated/exclusive unions, where optional never properties are used to prevent excess-property leakage between union members, for example:

interface Rect {
  width: number;
  height: number;
}
interface Circle {
  radius: number;
}

type Shape = Rect | Circle;

interface Entity {
  shape: Shape;
}

For C++, this correctly generates:

  struct Entity final {
  public:
    std::variant<Rect, Circle> shape     SWIFT_PRIVATE;
  };

which is exactly what I want. However, in plain TypeScript, this doesn't actually enforce exclusivity: an object like:

shape: { width: 100, height: 200, radius: 50 }

is accepted without error, since Shape is a union of object types and TS structurally allows extra properties in some contexts (and definitely doesn't reject this in a variable of type Shape built inline in certain positions).

The standard TS workaround for this is to add mutually exclusive never properties:

interface Rect {
  width: number;
  height: number;
  radius?: never;
}
interface Circle {
  radius: number;
  width?: never;
  height?: never;
}

This correctly makes Shape behave as an exclusive union in TypeScript, but Nitrogen fails to generate a spec for it, with the error shown above.

Expected behavior

Optional never properties should be ignored when generating the C++/Swift/Kotlin spec, rather than causing a hard error. They carry no runtime value and exist purely to help TypeScript enforce exclusivity between union members.

Environment

  • nitrogen / react-native-nitro-modules version: "0.35.3"

Are there any existing workarounds?

Not really a functional one: the ?: never pattern is the standard TypeScript idiom for enforcing mutual exclusivity between union members (see the Shape/Rect/Circle example above), and it's necessary because plain union types like Rect | Circle don't actually prevent excess/overlapping properties from being accepted. Without never, TypeScript happily accepts an object like { width: 100, height: 200, radius: 50 } as a valid Shape, which defeats the purpose of the union.

The only "workaround" is to not enforce exclusivity in TypeScript at all (drop the never fields), and instead do manual runtime validation of the shape's fields elsewhere but that reintroduces exactly the ambiguity the union type was meant to prevent, and gives up compile-time safety.

Additional information

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions