|
// ## LOW-LEVEL VALUE TYPES |
|
/* These are static types that take no |
|
* no arguments and represent |
|
* primitives */ |
|
|
|
export type PrimitiveValue = string | number | boolean | null; |
|
export type PrintableValue = PrimitiveValue | undefined; |
|
|
|
// All the possible values that can be returned |
|
// by the `typeof` keyword |
|
export type TypeLabel = |
|
| "string" |
|
| "number" |
|
| "bigint" |
|
| "boolean" |
|
| "symbol" |
|
| "undefined" |
|
| "object" |
|
| "function"; |
|
|
|
export type Falsy = false | 0 | "" | 0n | null | undefined; |
|
// We can't include `NaN` here because typescript |
|
// `NaN` is just a number, but it also can't be |
|
// used as a literal the same way other numbers |
|
// can |
|
|
|
// ## OBJECT TYPES |
|
export type AnyObject = Record<string, unknown> | unknown[]; |
|
export type EmptyObject = Record<never, never> | []; |
|
|
|
// ## VALUE COMPOSITION TYPES |
|
/* These types take type arguments and use |
|
them to compose more complex types */ |
|
|
|
export type Dictionary<T> = Record<string, T>; |
|
|
|
export type NonEmptyArray<T> = [T, ...T[]]; |
|
/* This is not actually particularly |
|
useful. The idea behind this was to |
|
use it as the type of a function's |
|
parameter, but in an actual codebase, |
|
arrays that we know aren't empty |
|
will probably still be typed with the |
|
standard `[]` typing, so passing it to |
|
a function that expects `NonEmptyArray` |
|
will trigger a typescript warning */ |
|
|
|
// A value stored in a passed array or object |
|
// type |
|
export type ValueFrom<Obj extends AnyObject> = Obj[keyof Obj]; |
|
|
|
export type KeyValuePair<Dict extends Dictionary<unknown>> = ValueFrom<{ |
|
[Key in keyof Dict]: [Key, Dict[Key]]; |
|
// $ This may look weird, but doing it this way means that |
|
// $ typescript will know the type of the value in the tuple |
|
// $ based on the key of the tuple, rather than pairs just being |
|
// $ typed as `[keyof Dict, ValueFrom<Dict>]` |
|
}>; |
|
|
|
export type DeepPartial<Dict extends Dictionary<unknown>> = { |
|
[Key in keyof Dict]?: Dict[Key] extends Dictionary<unknown> |
|
? DeepPartial<Dict[Key]> |
|
: Dict[Key]; |
|
}; |
|
|
|
// Alternate versions of `Extract` that enforces overlap between |
|
// the type arguments |
|
export type Narrow<Base extends Sub, Sub> = Extract<Base, Sub>; |
|
|
|
// Version of `Omit` where the keys being omitted |
|
// must actually be keys of the base type. This |
|
// should be used instead of `Omit` unless you are |
|
// dealing with dynamic types that may not be keys |
|
// of the base type. |
|
export type StrictOmit<BaseType, ToOmit extends keyof BaseType> = Omit< |
|
BaseType, |
|
ToOmit |
|
>; |
|
|
|
// Take an object type and make specific fields |
|
// non-optional |
|
export type RequireSpecificKeys< |
|
Dict extends Dictionary<any>, |
|
Keys extends keyof Dict, |
|
> = Dict & Required<Pick<Dict, Keys>>; |
|
|
|
// Take an object type and make specific fields |
|
// optional |
|
export type PartialSpecificKeys< |
|
Dict extends Dictionary<any>, |
|
Keys extends keyof Dict, |
|
> = Omit<Dict, Keys> & Partial<Pick<Dict, Keys>>; |
|
|
|
// Removes the `readonly` property from a type |
|
export type Mutable<Obj extends AnyObject> = { |
|
-readonly [P in keyof Obj]: Obj[P]; |
|
}; |
|
|
|
export type ShallowMerge< |
|
Source extends Record<string, any>, |
|
Update extends Record<string, any>, |
|
> = Omit<Source, keyof Update> & Update; |
|
|
|
// Replace the type of a specific field(s) |
|
// in an object type |
|
export type ReplaceFieldType< |
|
Dict extends Dictionary<any>, |
|
Key extends keyof Dict, |
|
Replacement, |
|
> = Omit<Dict, Key> & Record<Key, Replacement>; |
|
|
|
// Get keys of the base type that are of a specific type |
|
export type ExtractKeyOf<BaseType, KeyExtraction> = Extract< |
|
keyof BaseType, |
|
KeyExtraction |
|
>; |
|
export type StringKeyOf<BaseType> = ExtractKeyOf<BaseType, string>; |
|
|
|
export type ExcludeKeyOf<BaseType, KeyExclusion> = Exclude< |
|
keyof BaseType, |
|
KeyExclusion |
|
>; |
|
|
|
export type PrefixKeys< |
|
Dict extends Dictionary<unknown>, |
|
Prefix extends string, |
|
> = { |
|
[Key in StringKeyOf<Dict> as `${Prefix}${Key}`]: Dict[Key]; |
|
}; |
|
|
|
export type ConditionalUnion< |
|
Base, |
|
Incoming, |
|
Condition extends boolean, |
|
> = Condition extends true ? Base | Incoming : Base; |
|
|
|
// Invert a boolean type |
|
export type Not<Bool extends boolean> = Bool extends true ? false : true; |
|
|
|
export type DeepOmitOptional<Obj extends Record<any, unknown>> = { |
|
[Key in keyof Obj as Obj[Key] extends Required<Obj>[Key] |
|
? Key |
|
: never]: Obj[Key] extends Record<any, unknown> |
|
? DeepOmitOptional<Obj[Key]> |
|
: Obj[Key]; |
|
}; |
|
|
|
/** |
|
* Pick some keys from an object type and make those |
|
* fields required, except for some exceptions which |
|
* will simply be picked without being marked as |
|
* required |
|
*/ |
|
export type PickAndMakeRequiredWithExceptions< |
|
Base, |
|
ToPick extends keyof Base, |
|
ToNotMakeRequired extends ToPick, |
|
> = Pick<Base, ToNotMakeRequired> & |
|
Required<Omit<Pick<Base, ToPick>, ToNotMakeRequired>>; |
|
|
|
// ## FUNCTION TYPES |
|
|
|
// Can be either a static value, or a getter |
|
// function for deriving a value |
|
export type GetterOrStatic<PassedType, ReturnType> = |
|
| ((p: PassedType) => ReturnType) |
|
| ReturnType; |
|
|
|
export type Comparator<T> = (a: T, b: T) => boolean; |
|
export type SortComparator<T> = (a: T, b: T) => number; |
|
export type Checker<T> = (item: T) => boolean; |
|
|
|
export type Converter<Base, Target> = (base: Base) => Target; |
|
|
|
export type Updater<T> = (a: T) => T; |
|
|
|
// ## MISC TYPES |
|
|
|
// When you want to specify auto-complete suggestions in |
|
// the editor while also allowing values outside of the |
|
// suggestions to be provided. |
|
// NOTE: Trust me, the use of `Omit` is not a mistake, for |
|
// whatever reasons you have to use it instead of `Exclude` |
|
// for this to work with strings. Not sure about other types |
|
// as I have only tested with strings. |
|
type WithLooseAutocomplete<AcceptedType, Suggestions extends AcceptedType> = |
|
| Suggestions |
|
| Exclude<Omit<AcceptedType, Suggestions & keyof AcceptedType>, Suggestions>; |