Skip to content

Instantly share code, notes, and snippets.

@maradondt
Created April 27, 2024 14:13
Show Gist options
  • Save maradondt/efc4d89d2e893048e80fb5b5cff61984 to your computer and use it in GitHub Desktop.
Save maradondt/efc4d89d2e893048e80fb5b5cff61984 to your computer and use it in GitHub Desktop.
Typeguard factory typescrypt
/* eslint-disable @typescript-eslint/no-explicit-any */
type Primitive = string | number | boolean | bigint | symbol | undefined | null;
interface Constructor<T = unknown, P extends unknown[] = never> {
new (...args: P): T;
}
type Guard<P = any, T extends P = P> = (x: P) => x is T;
type SomeOf<T extends Guard[]> = T[number] extends Guard<infer P, infer R>
? (x: P) => x is R
: never;
/**
*
* @example
* ```ts
*
* const b: B[] = [new B1(), new B2()];
* // const onlyB1: B1[];
* const onlyB1 = b.filter(instanceOf(B1));
* ```
*/
export function instanceOf<T extends S, S>(clazz: Constructor<T>) {
return (x: S): x is T => x instanceof clazz;
}
/**
*
* @example
* ```ts
* const isObjectAttach = createGuard<
* IssueObjectAttachmentDto,
* IssueAttachmentDto
* >((attach) => attach.type === 'Object');
*
* // IssueObjectAttachmentDto[]
* const onlyObjectAttach = attachList.filter(isObjectAttach)
* ```
*/
export function createGuard<T extends P, P>(matcher: (x: P) => boolean) {
return (x: P): x is T => matcher(x);
}
export function is<T extends Primitive & S, S>(matcher: T) {
return (x: S): x is T => x === (matcher as Primitive);
}
/**
*
* @example
* ```ts
* // 1. classes
* const arr = [new Event1(), new Event2(), new Event3()];
* // filtered (Event1 | Event2)[]
* const filtered = arr.filter(someOf(instanceOf(Event1), instanceOf(Event1)));
* // 2. primitives
* const arr = [1, 2, 3, 4, 5];
* // (1 | 2)[]
* const filtered = arr.filter(someOf(is(1), is(2)));
* ```
*/
export function someOf<T extends Guard[]>(...guards: T) {
return ((x) => guards.some((guard) => guard(x))) as SomeOf<T>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment