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

Appetite for adding a Union type to tsutils #117

Open
lucas-rudd opened this issue Mar 24, 2020 · 0 comments
Open

Appetite for adding a Union type to tsutils #117

lucas-rudd opened this issue Mar 24, 2020 · 0 comments

Comments

@lucas-rudd
Copy link

I have some utilities that we use a lot for helping with Union types and typeguarding from dynamic data sources, such as data to/from an API call.

However, I also use these utilities in my own personal projects, and would like them to be published to the public registry for community use, as well as for my own use.

I could publish these myself, but it seems like this package has a lot of the same ideas that we have with these modules, and feel as though they would fit well here.

I'm wondering what the appetite for integrating some of these changes would be.

Here are the utilities that we use

Here is what we have in our README to explain how these methods are used, along with some example code.

# TypeGuard Utils

The Union util allows us to define a typeguard for string or numeric union types, which allows us to determine whether or not a string or number is in that union at runtime.

You should export both the type, and the const value so that typescript will merge the two definitions together in the type definition. While developing, Typescript will determine whether or not the Util is being used as a type, to provide compile-time checks, or as a method of checking/guarding a value at runtime.

Example usage:
// contracts.ts
export const StatusValue = Union('connected', 'disconnected', 'pending');
export type StatusValue = typeof StatusValue.type;
export const StatusValues = StatusValue.mapValues();

// handler.ts
let { status }: { status: StatusValue } = this.getBody();
// set default value if status is not in the union of StatusValue types
if (!StatusValue.guard(status)) {
    status = 'connected';
}
service.doSomething(status);
At compile-time, the StatusValue type works the same as if we'd defined a string union normally with `"connected" | "disconnected" | "pending"`. 
The guard() function returns whether or not the value provided is a member of the union, and may be used as a type guard.

Example usage of check:
// contracts.ts
export const StatusValue = Union('connected', 'disconnected', 'pending');
export type StatusValue = typeof StatusValue.type;

// handler.ts
let { status }: { status: StatusValue } = this.getBody();
// check if status is valid, if not, return an error to the user
try {
  StatusValue.check(status);
  service.doSomething(status);
} catch (e) {
  return this.error(new Error('Status must be of type "connected", "disconnected", "pending"'));
}
The check() function returns the passed value if it's valid or else throws a TypeError.


Using the mapValues() function, you can replicate an Enum value (while still keeping the benefits of TypeGuards that the Union class provides).

To use this method, call mapValues() on your type and export it from your contracts file like so.
// contracts.ts
export const StatusValue = Union('connected', 'disconnected', 'pending');
export type StatusValue = typeof StatusValue.type;
export const StatusValues = StatusValue.mapValues();
Here's an example of using the StatusValues Union to default a value in the doSomething service method to 'connected', without hardcoding the 'connected' string.
// contracts.ts
export const StatusValue = Union('connected', 'disconnected', 'pending');
export type StatusValue = typeof StatusValue.type;
export const StatusValues = StatusValue.mapValues();

//service.ts
export class Service {
    public doSomethting(status = StatusValues.connected) {
        ...
    }
}

Would this package benefit from these utilities? Or, is this out of the scope of this project?

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

1 participant