Skip to main content

ts-helpers

Installation#

yarn add @uplift-ltd/ts-helpers

API#

assertUnreachable#

Invoke this assertion for an unreachable case.

import { assertUnreachable } from "@uplift-ltd/ts-helpers";
switch (condition) {
case true:
return bleh;
default:
assertUnreachable("invalid condition");
}

notEmpty#

Filter and array so typescript knows there are no null or undefined values.

import { notEmpty } from "@uplift-ltd/ts-helpers";
const array: (string | null)[] = ["foo", "bar", null, "zoo", null];
const filteredArray: string[] = array.filter(notEmpty);

typedIncludes#

Assert whether a variable is a member of an array in a type-safe way. This also avoids the "string" is not a member of TYPE errors.

const colors = ["blue", "green", "red"] as const;
// You avoid the error here, that myColor is string, not a member of colors
if (typedIncludes(colors, myColor)) {
// typeof myColor = "blue" | "green" | "red"
// You also get a type error here that yellow is not "blue" | "green" | "red"
if (myColor === "yellow") {
}
}

ArrayElement#

Returns the type of an element of the array

type Item = ArrayElement<string[]>; // => string
type Item = ArrayElement<(ThisLineItem | ThatLineItem)[]>; // => (ThisLineItem | ThatLineItem)

ArrayToUnion#

Converts an array of strings into a discriminated type union.

const httpMethods = ["GET", "POST", "PUT", "PATCH", "OPTIONS", "HEAD", "DELETE"] as const; // note: `as const` is required
type HttpMethod = ArrayToUnion<typeof httpMethods>; // => "GET" | "POST" | "PUT" | "PATCH" | "OPTIONS" | "HEAD" | "DELETE"

DeepPartial#

Deeply marks attributes as optional

interface RequiredFields {
firstName: string;
lastName: string;
age: number;
address: {
street: string;
postalCode: string;
city: string;
state: string;
country: string;
};
}
type OptionalFields = DeepPartial<RequiredFields>;
/*
* => {
* firstName?: string;
* lastName?: string;
* age?: number;
* address?: {
* street?: string;
* postalCode?: string;
* city?: string;
* state?: string;
* country?: string;
* }
* }
*
*/

RequireAtLeastOne#

Tell typescript to require at least one of the keys to be present.

import { RequireAtLeastOne } from "@uplift-ltd/ts-helpers";
interface Props {
a?: boolean
b?: boolean
c: boolean
}
type ABProps = RequireAtLeastOne<Props, 'a' | 'b'>
<Component a c /> /* passes */
<Component b c /> /* passes */
<Component a b c /> /* passes */
<Component c /> /* throws */

RequireOnlyOne#

Tell typescript to require only one (not all) of the keys to be present.

import { RequireOnlyOne } from "@uplift-ltd/ts-helpers";
interface Props {
a?: boolean
b?: boolean
c: boolean
}
type ABProps = RequireOnlyOne<Props, 'a' | 'b'>
<Component a c /> /* passes */
<Component b c /> /* passes */
<Component a b c /> /* throws */
<Component c /> /* throws */

Unpromise#

Returns the result type of a promise.

type Result = Unpromise<Promise<boolean>>; // => boolean

Can be combined with ReturnType to get the result of a function that returns a promise.

type TheTypeWeWant = { a: boolean };
type PromiseReturningFunction = () => Promise<TheTypeWeWant>;
type TheTypeWeHave = Unpromise<ReturnType<PromiseReturningFunction>>;
// TheTypeWeHave is now TheTypeWeWant

UnreachableCaseError#

Throw this type of error for an unreachable case.

import { UnreachableCaseError } from "@uplift-ltd/ts-helpers";
switch (condition) {
case true:
return bleh;
default:
throw new UnreachableCaseError("invalid condition");
}

ValuesOf#

Returns a type union of the values of a record/object

const Colors = {
BLUE: "blue",
RED: "red",
GREEN: "green",
};
type Color = ValuesOf<typeof Colors>; // => "blue" | "red" | "green"

Relay#

Helpers for working with Relay Connections

GetConnectionNode
Extracts the Node from a Relay Connection, even if some or all of the Connection is nullable

GetConnectionNodeArray
Helper that just returns an array of the Connection Node, also works if Connection is nullable

type User = {
firstName: string;
lastName: string;
age: number;
};
// Non-nullable
type Organization = {
users: {
edges: { node: User }[];
};
};
// Nullable
type NullableOrganization = {
users?: {
edges?: { node: User }[] | null;
} | null;
};
Organization["users"]["edges"][0]["node"];
// => User
GetConnectionNode<Organization["users"]>;
// => User
GetConnectionNodeArray<Organization["users"]>;
// => Array<User>
GetConnectionNode<NonNullable<NullableOrganization["users"]>>;
// => User
GetConnectionNodeArray<NonNullable<NullableOrganization["users"]>>;
// => Array<User>

makeUnionMemberGuard#

Filter on a discriminated union.

import { makeGraphqlUnionGuard, makeUnionMemberGuard } from "@uplift-ltd/ts-helpers";
type A = {
__typename: "A";
x: number;
};
type B = {
__typename: "B";
y: number;
};
type AB = A | B;
const a = { __typename: "A", x: 1 } as const;
const b = { __typename: "B", y: 2 } as const;
const ab: AB[] = [a, b];
ab.filter(makeUnionMemberGuard("__typename", "A")); // A[]
ab.filter(makeUnionMemberGuard("__typename", "B")); // B[]
ab.filter(makeGraphqlUnionMemberGuard("A")); // A[]
ab.filter(makeGraphqlUnionMemberGuard("B")); // B[]