-
aec6f75
Thanks @lukemorales! - Improve inference of return types with new generic valueThe return type of
exhaustive
andexhaustive.tag
will now be inferred based on the return type of the callback function.type Union = "IDLE" | "LOADING" | "SUCCESS" | "ERROR"; type HumanReadableUnion = "idle" | "loading" | "success" | "error"; function unionToHumanReadableString(union: Union): HumanReadableUnion { return exhaustive(union, { IDLE: () => "idle", LOADING: () => "loading", SUCCESS: () => "success", ERROR: (value) => value.toLowerCase(), // type `string` is not assignable to type `HumanReadableUnion` }); }
-
d210075
Thanks @lukemorales! - Fix exhaustive compile checksWith the added support of exhaustive boolean checks, TypeScript stopped complaining if a key was missing in the exhaustive object due to how the new types were declared. The types were adjusted to bring back the expected behavior of TypesScript complaining at compile-time if you forget to handle all the use-cases.
-
#6
abc000e
Thanks @lukemorales! - ## Add support for booleansBoth
exhaustive
andexhaustive.tag
can now be exhaustive checked against booleans:function handleStatus(isSelected: boolean) { return exhaustive(isSelected, { true: () => { // ...run handler for true case }, false: () => { // ...run handler for false case }, }); }
type ProfileStatus = | { checked: true; data: string } | { checked: false; error: string }; function handleProfileStatus(status: ProfileStatus) { return exhaustive.tag(status, "checked", { true: (value) => saveProfile(value.data), // ^? value is { checked: true; data: string } false: (value) => throwException(value.error), // ^? value is { checked: false; error: string } }); }
-
#4
b287bbb
Thanks @lukemorales! - ## ExposedExhaustive
types and added new generic slot in core function for type of outputThe types
ExhaustiveUnion
andExhaustiveag
are now exposed for your own convenience if you'd like to override the generic slots ofexhaustive
. The inferred output was also added as a new slot in the function generics, allowing you to also override the output value ofexhaustive
:import { exhaustive, type ExhaustiveTag } from "exhaustive"; exhaustive< RequestState, "state", ExhaustiveTag<RequestState, "state">, JSX.Element >(request, "state", { IDLE: () => null, LOADING: (value) => <Loading />, SUCCESS: (value) => <List data={value.data} />, ERROR: (value) => <Error message={value.error} />, });
The
_tag
method was exposed as a some sort of secondary method to enhance the experience with Tagged Unions. Since the DX of using it is vastly superior compared to the Tagged Union overload inexhaustive
, and it seems that we cannot improve the overload inference on the core funcion, the underscore has been removed from the method name and now you should used it asexhaustive.tag
to make it official as the preferred way to exhaustive check Tagged Unions:const area = (s: Shape) => { - return exhaustive._tag(s, 'kind', { + return exhaustive.tag(s, 'kind', { square: (shape) => shape.size ** 2, rectangle: (shape) => shape.width * shape.height, circle: (shape) => Math.PI * shape.radius ** 2, }); };
-
#4
b287bbb
Thanks @lukemorales! - ## Addexhaustive.tag
overload to core functionThe same functionality of
exhaustive.tag
is available in the main function by adding a third argument toexhaustive
that will trigger the Tagged Union overload.const area = (s: Shape) => { return exhaustive(s, "kind", { square: (shape) => shape.size ** 2, rectangle: (shape) => shape.width * shape.height, circle: (shape) => Math.PI * shape.radius ** 2, }); };
PS: Note that TypeScript has a limitation inferring the Tagged Union overload via argument types because they are generic values. Typescript will only fallback to the Tagged Union overload when you add a third argument. This means autocomplete for the Tagged Union keys will not exist until you declare an empty object as the third argument:
exhaustive(shape, "kind", {}); // ^ this will trigger the Tagged Union overload
This feature is being added as a reflect of how the API was originally intended. Use it at your own convenience, but if you prefer the better DX of inferred types from the start, calling
exhaustive.tag
is still preferrable.
- #2
c1c4c65
Thanks @lukemorales! - Initial release ofexhaustive
andcorrupt
functions