wit-bindgen icon indicating copy to clipboard operation
wit-bindgen copied to clipboard

[Bug] TS generation of `option<option<option<T>>>`

Open willemneal opened this issue 4 years ago • 1 comments

A very unlikely type, but currently.

record person {
  name: string,
  age: option<option<option<u32>>>,
}

becomes

export interface Person {
  name: string,
  age?: number | null | null,
}

Of course I notice this after the PR is merged ;-)

willemneal avatar Feb 15 '22 17:02 willemneal

I think a representation like this that preserves the layering would be good for anything beyond the outermost layer.

type Option<T> = { inner: T } | null;

export interface Person {
  name: string,
  age?: Option<Option<number>>
}

We could offer users conveniences for creating Some instances. It would be type safe and idiomatic enough to create None using null.

function Some<T>(value: T): Option<T> {
   return { inner: value };
}

Users would be able to check for them a few different ways, all of which work with nesting and don't care whether you evaluate truthiness, use strict equality/non-equality, or use the loose one.

// matches for Some
if (optionalValue) { ... }
if (optionalValue != null) { ... }
if (optionalValue !== null) { ... }
// matches for None
if (!optionalValue) { ... }
if (optionalValue == null) { ... }
if (optionalValue === null) { ... }

Once you've established that a value is Some, you can safely access the inner value.

if (optionalValue) {
   console.log(optionalValue.inner);
}

esoterra avatar Mar 10 '22 02:03 esoterra

I think this is fixed nowadays as

record person {
  name: string,
  age: option<option<option<u32>>>,
}

generates

export interface Person {
  name: string,
  age?: Option<number | null>,
}
export type Option<T> = { tag: "none" } | { tag: "some", val; T };

alexcrichton avatar Oct 13 '22 17:10 alexcrichton