Skip to content

NZXTCorp/enunion

Repository files navigation

enunion

Enunion (enum + union) is the combination of Rust enums and TypeScript Discriminated Unions! By combining this with napi you can define an enum type in Rust, feed it into TypeScript, and receive instances of it from TypeScript. enunion will handle translating at the boundary, and neither language has to think about the representation in the other language.

Getting Started

This section assumes you have an existing napi project.

First add enunion to your Cargo.toml

[dependencies]
enunion = { git = "https://github.com/NZXTCorp/enunion.git" }

The enunion macro will not work if napi and napi_derive are not specified in the [dependencies] section of the Cargo.toml.

This macro has a companion library called enunion-helper which is appending the generated code from enunion to index.d.ts:

enunion_helper::post_build(necessary_dir).await?;

In unusual circumstances enunion may leave behind some of the generated files. Add these to your .gitignore like so

/enunion-generated-ts

Now you should be good to go, when you add the enunion trait to an enum, the macro will take care of the rest. Here's an example of what that might look like

#[enunion::enunion]
pub enum Foo {
    Bar,
    Baz {
        a: i32,
        b: u32,
        c: String,
        my_multi_word_field: i32,
    }
}

#[napi]
pub fn take_foo(f: Foo) -> Foo {
   assert!(matches!(f, Foo::Baz {a: 3, b: 2, c: _, my_multi_word_field: 2}));
    match f {
        Foo::Baz {c, ..} => assert_eq!(c, "Hello from TypeScript"),
        _ => unreachable!(),
    }
    Foo::Baz {
        a: 1,
        b: 2,
        c: String::from("Hello from Rust"),
        my_multi_word_field: 8,
    }
}

And on the TypeScript side we can consume it like so

it("calls takeFoo", () => {
  let r = takeFoo({
    a: 3,
    b: 2,
    c: "Hello from TypeScript",
    myMultiWordField: 2,
    fooType: FOO_TYPE_BAZ,
  });
  expect(r.fooType).toBe(FOO_TYPE_BAZ);
  if (r.fooType === FOO_TYPE_BAZ) {
    // Thanks to type narrowing, TypeScript now allows us to access the "Baz" specific fields
    // that don't exist on "Bar".
    expect(r.a).toBe(1);
    expect(r.b).toBe(2);
    expect(r.c).toBe("Hello from Rust");
    expect(r.myMultiWordField).toBe(8);
  }
});

About

No description, website, or topics provided.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published