Skip to content

Instantly share code, notes, and snippets.

@milesegan
Last active September 18, 2021 14:05
Show Gist options
  • Save milesegan/09629865d61c348721d2aff022f83c5d to your computer and use it in GitHub Desktop.
Save milesegan/09629865d61c348721d2aff022f83c5d to your computer and use it in GitHub Desktop.
typescript utils
// Null filtering.
function isDefined<T>(value: T | undefined | null): value is T {
return !!value;
}
// Immutability
export type Immutable<T> = T extends Function | boolean | number | string | null | undefined
? T
: T extends Array<infer U>
? ReadonlyArray<Immutable<U>>
: T extends Map<infer K, infer V>
? ReadonlyMap<Immutable<K>, Immutable<V>>
: T extends Set<infer S>
? ReadonlySet<Immutable<S>>
: {readonly [P in keyof T]: Immutable<T[P]>};
// Type narrowing.
const isInstanceOf =
<T>(ctor: new (...args: any) => T) =>
(x: any): x is T =>
x instanceof ctor;
type Foo = {type: "foo"; val: number};
type Bar = {type: "bar"; val: string};
type FooOrBar = Foo | Bar;
function discriminate<K extends PropertyKey, V extends string | number | boolean>(
discriminantKey: K,
discriminantValue: V,
) {
return <T extends Record<K, any>>(obj: T & Record<K, V extends T[K] ? T[K] : V>): obj is Extract<T, Record<K, V>> =>
obj[discriminantKey] === discriminantValue;
}
const fooStuff = ([] as FooOrBar[]).filter(discriminate("type", "foo"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment