Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generics on tagged union #15

Closed
dtgoitia opened this issue Jan 16, 2023 · 2 comments
Closed

Generics on tagged union #15

dtgoitia opened this issue Jan 16, 2023 · 2 comments

Comments

@dtgoitia
Copy link

dtgoitia commented Jan 16, 2023

Hi!

Thank you very much for this package. I love these Rust-like features.

I'm not an expert in TypeScript, and I was wondering if I'm just trying to do something impossible:

// given a generic `Maybe.Some`
const Maybe = makeTaggedUnion({
  Some: <T>(data: T) => data,
  None: none,
});

// when `Maybe.Some` is used with a concrete value
function foo(perhaps: boolean) {
  return perhaps
    ? Maybe.Some(1)
    : Maybe.None;
}

// then the TypeScript infers the type of `value`
foo(true).match({
  Some: (value) => console.log(value),
  //     ^^^^^ unfortunately, TypeScript believes `value` is of type `unknown`
  None: () => {},
});

Is there a way in which the TypeScript compiler can infer that value is a number?

Thank you very much in advance :)

@suchipi
Copy link
Owner

suchipi commented Jan 16, 2023

There is some prior discussion on this topic here: #12

As far as I know, this isn't possible due to limitations in TypeScript, but it's been a while, so it'd be worth checking again.

@suchipi
Copy link
Owner

suchipi commented Jan 17, 2023

Here's something I came up with that requires writing the Definitions object twice and requires that you manually specify the types of any Maybes, but otherwise should do everything you need:

import { makeTaggedUnion, MemberType, none, TaggedUnion } from "./index";

// First, make the tagged union using 'any' for all the stuff that you want to be generic:
const Maybe = makeTaggedUnion({
  Some: (data: any) => data,
  None: none,
});

// Then, instead of using `type Maybe = MemberType<typeof Maybe>` for the type,
// manually specify a `TaggedUnion` object as the parameter to `MemberType`, using
// generics in the appropriate places
type Maybe<T> = MemberType<
  TaggedUnion<{
    Some: (data: T) => T;
    None: typeof none;
  }>
>;

// Now, `Maybe` should work as expected. Note, however, that you have to manually
// annotate any instances of the `Maybe` type when creating them, or else they'll have
// the `any`s from the `makeTaggedUnion` call.
const data: Maybe<string> = Maybe.Some("woo");

data.match({
  Some: (str) => str,
  None: () => "doot",
});

@suchipi suchipi closed this as completed Jan 17, 2023
@suchipi suchipi mentioned this issue Jan 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants