A collection of type definitions which I've found helpful across many projects.
Install via your favorite package manager.
Each package supports CommonJS require
, ESM import
, and TypeScript usage.
You also have a choice: barrel imports or direct imports.
Barrel imports mean you're going to require/import everything from the same package-level namespace:
// CommonJS
const { isPlainObject, isListOf } = require("@rickosborne/guard");
// ESM / TypeScript
import { isPlainObject, isListOf } from "@rickosborne/guard";
Implications:
- Nice and simple.
- Your build system needs to do tree-shaking well ... or you'll end up adding the entire package even if you only import two functions.
The other option is to use direct imports:
// CommonJS
const { isPlainObject } = require("@rickosborne/guard/is-object");
const { isListOf } = require("@rickosborne/guard/is-list-of");
// ESM / TypeScript
import { isPlainObject } from "@rickosborne/guard/is-object.js";
import { isListOf } from "@rickosborne/guard/is-list-of.js";
Implications:
- You (probably) don't have to worry about tree-shaking as your build (likely) ends up with only the functions you need.
If you're using a modern build system, there aren't any strong reasons to prefer one way over the other. It's really just down to your personal preference.
Do you need to use file extensions? And if so, which extensions?
Honestly ... this is a dumpster fire question. It really comes down to your own setup and configuration.
Within each package itself:
- The CommonJS files all have
.cjs
extensions. - The ESM files all have
.mjs
extensions. - Node subpath exports have been set up to send
.js
imports to the.cjs
(viarequire
) or.mjs
(viaimport
) files, depending on your setup.
So, in theory, the only extension which won't work would be .ts
because the source isn't included.
If you run into a problem with a particular configuration, file a GitHub issue with:
- Your
tsconfig.json
'smodule
,moduleResolution
, andtarget
settings. - Your
package.json
'stype
andimports
settings. - An example of another package which imports correctly for you.
This package is licensed as CC-BY-NC-SA-4.0 unless otherwise noted. That is, Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.
export interface JSONObject extends Record<string, JSONSerializable>
A record which contains only keys and values which can be serialized as JSON.
type AbstractConstructorLike<Params extends unknown[], Instance> = abstract new (...params: Params) => Instance;
type AnyConstructorLike<Params extends unknown[], Instance> = ConstructorLike<Params, Instance> | AbstractConstructorLike<Params, Instance>;
type AnyFunction = (...params: any) => unknown;
Anything which could be called like a function.
type AsyncRunnable = () => Promise<void | undefined>;
An async function which can be run without any input or output.
type BiConsumer<T, U> = (t: T, u: U) => void;
Function which accepts the given input type without any output.
type BinaryOperator<T> = (left: T, right: T) => T;
Function which accepts two of the given type and returns the same.
type BiPredicate<T, U> = (t: T, u: U) => boolean;
Function which evaluates two values against a condition.
type BuiltIn = Date | Error | Function | Generator | {
readonly [Symbol.toStringTag]: string;
} | RegExp;
Copied from ts-toolbox.
type CombinedKeys<T extends object, U extends object> = SpecificKeys<T> | SpecificKeys<U>;
All keys from both types, combined.
type Comparator<T> = (a: T, b: T) => number;
A function which compares two values and returns the order in which they should be sorted. Negative values mean a
should be sorted before b
, while positive values mean the reverse. Zero means the two values are equivalent.
type ConstructorLike<Params extends unknown[], Instance> = new (...params: Params) => Instance;
A constructor-like value which, when invoked via new, accepts the given parameter type(s) and produces the given instance type.
type ConstructorParams<C> = C extends ConstructorLike<infer P, unknown> ? P : never;
Infer the types of the given constructor's parameters, in a tuple.
type Consumer<T> = UnaryConsumer<T>;
Shorthand for UnaryConsumer.
type DeepValued<T> = T extends (infer U)[] ? DeepValued<U>[] : T extends object ? {
[K in keyof T]: DeepValued<T[K]>;
} : NonNullable<T>;
Equivalent to a recursive Required
.
type Defined<T> = T extends undefined ? never : T;
Filter out undefined
from types. Equivalent to Exclude<T, undefined>
.
type Either<T extends object, U extends object> = Overwrite<NeverEvery<T>, U> | Overwrite<NeverEvery<U>, T>;
Produce a union of intersections, where all keys are present for both types, and can be used in destructuring assignments, but the individual property values are still mutually exclusive.
type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
Type-level equality check. I did not come up with this. See this comment on the TypeScript issue for the source.
type ExactlyOneOf<T extends object> = {
[K in keyof T]: {
[One in K]: T[One];
} & {
[Other in keyof T as Other extends K ? never : Other]?: never;
};
}[keyof T];
Given a record with some number of properties, fan out all permutations of that record where exactly 1 property is possible, while the rest are omitted.
type FlagKeys<T extends object> = keyof {
[K in keyof T as boolean extends T[K] ? K extends SpecificKeys<T> ? K : never : never]: K;
};
Extract only the keys for properties which could have Boolean values.
type FunctionLike<Params extends unknown[], Return> = (...params: Params) => Return;
A function-like value which accepts the given parameter type(s) and produces the given return type.
type FunctionParams<F> = F extends FunctionLike<infer P, unknown> ? P : never;
Infer the types of the given function's parameters, in a tuple.
type IfEquals<X, Y, Z> = Equals<X, Y> extends true ? Z : never;
If the first two parameters, X
and Y
, are equal, return the third, Z
.
type IfSpecificKeys<T extends object> = SpecificKeys<T> extends never ? never : T;
If the object has any specific keys, return it.
type IndexedPredicate<T> = (value: T, index: number) => boolean;
Function which evaluates a value and its position against a condition. Typically used for array or iterator filters.
type ItemType<T extends unknown[] | Readonly<unknown[]>> = T extends (infer U)[] ? U : never;
Find the type of the items in an array.
type JSONArray = JSONSerializable[];
An array which contains only values which can be serialized as JSON.
type JSONPrimitive = string | number | boolean | null;
A scalar literal value which can be serialized as JSON.
type JSONSerializable = JSONPrimitive | JSONObject | JSONArray;
Any value which can be serialized as JSON.
type JSONSerializableOf<T> = T extends JSONPrimitive ? T : T extends (infer U)[] ? JSONSerializableOf<U>[] : T extends undefined ? never : T extends object ? {
[K in keyof T]: JSONSerializableOf<T[K]>;
} : never;
type NeverEvery<T extends object> = {
[K in keyof T as K extends SpecificKeys<T> ? K : never]?: never;
};
Map a type such that it has the same keys, but they all have never
as their value type. Generally combined with Overwrite
. Used when you want to acknowledge the possible presence of those properties, but you want to mask them out so they're never read or written in any meaningful way.
type NonNull<T> = T extends null ? never : T;
Filter out null
from types. Equivalent to Exclude<T, null>
.
type NoRecord<T extends object> = object extends T ? Record<never, unknown> : {
[K in keyof T as string extends K ? never : symbol extends K ? never : number extends K ? never : K]: T[K];
};
Remove the "wildcard" parts of an object, leaving only the concrete, specified parts. That is, it removes any keys which could be any string, any number, or any symbol.
type NotEquals<X, Y> = Equals<X, Y> extends true ? X : never;
If the parameters are not equal, return the first.
type NotSame<X, Y> = X extends Y ? Y extends X ? never : X : never;
If the parameters are not the same, return the first.
type OptionalKeys<T extends object> = keyof {
[K in keyof T as undefined extends T[K] ? K extends SpecificKeys<T> ? K : never : null extends T[K] ? K extends SpecificKeys<T> ? K : never : never]: K;
};
Extract only the keys for properties which could have undefined or null values.
type Overwrite<Loser extends object, Winner extends object> = Omit<Loser, keyof Winner & keyof Loser> & Winner;
Combine two types such that properties with matching keys are overwritten entirely by the Winner.
type Predicate<T> = UnaryPredicate<T>;
Shorthand for UnaryPredicate.
type ReadOnlyKeys<T extends object> = keyof {
[K in keyof T as IfEquals<{
readonly [key in K]: T[K];
}, {
[key in K]: T[K];
}, K extends SpecificKeys<T> ? K : never>]: K;
};
Extract only the keys for properties which are read-only.
type RequiredKeys<T extends object> = keyof {
[K in keyof T as undefined extends T[K] ? never : K extends SpecificKeys<T> ? K : never]: K;
};
Extract only the keys for properties which cannot have undefined or null values.
type Resolve<T extends any, Seen = never> = T extends BuiltIn ? T : [T] extends [Seen] ? T : T extends any[] ? T extends Record<string | number | symbol, any>[] ? ({
[K in keyof T[number]]: Resolve<T[number][K], T | Seen>;
} & unknown)[] : T : T extends readonly any[] ? T extends readonly Record<string | number | symbol, any>[] ? readonly ({
[K in keyof T[number]]: Resolve<T[number][K], T | Seen>;
} & unknown)[] : T : {
[K in keyof T]: Resolve<T[K], T | Seen>;
} & unknown;
Try to coerce tsc into showing an integrated type, instead of a type intersection / union / etc.
type Runnable = () => (void | undefined);
A function which can be run without any input or output.
type SharedKeys<T extends object, U extends object> = SpecificKeys<T> & SpecificKeys<U>;
Only the keys which exist in both types.
type SpecificKey<K extends string | number | symbol> = K extends string ? string extends K ? never : K : K extends symbol ? symbol extends K ? never : K : K extends number ? number extends K ? never : K : never;
Eliminate catch-all keys from a union.
type SpecificKeys<T extends object> = T extends object ? object extends T ? never : SpecificKey<keyof T> : never;
Eliminate catch-all keys from an object.
type Subtract<Left extends object, Right extends object> = Omit<Left, SharedKeys<Left, Right>>;
Remove all properties from the left type which have keys shared with the right type.
type Supplier<T> = () => T;
Function which returns a given type without any input.
type TriConsumer<T, U, V> = (t: T, u: U, v: V) => void;
Function which accepts the given input type without any output.
type UnaryConsumer<T> = (value: T) => void;
Function which accepts the given input type without any output.
type UnaryOperator<T> = (value: T) => T;
Function which accepts the given type and returns the same.
type UnaryPredicate<T> = (value: T) => boolean;
Function which evaluates a value against a condition.
type Valued<T> = T extends null | undefined ? never : T;
Filter out null
and undefined
from types. Equivalent to Exclude<T, null | undefined>
.
type WithOptionalProperty<Original, Name extends string, Value> = Omit<Original, Name> & {
[K in Name]?: Value;
};
Extend the given type with an optional property of the given name and value type. If the original type already had a property of that name, it is replaced not union-ed.
type WithProperty<Original, Name extends string, Value> = Omit<Original, Name> & {
[K in Name]: Value;
};
Extend the given type with a property of the given name and value type. If the original type already had a property of that name, it is replaced not union-ed.
type WithReadOnlyProperty<Original, Name extends string, Value> = Omit<Original, Name> & {
readonly [K in Name]: Value;
};
Extend the given type with a read-only property of the given name and value type. If the original type already had a property of that name, it is replaced not union-ed.
A_GT_B = 1
Helper for comparators to make it clear to readers which value is greater-than the other.
A_LT_B = -1
Helper for comparators to make it clear to readers which value is less-than the other.
EQ = 0
Helper for comparators to make it clear the two values are equivalent.