ox
Version:
415 lines (375 loc) • 8.99 kB
text/typescript
/** Combines members of an intersection into a readable type. */
// https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg
export type Compute<type> = { [key in keyof type]: type[key] } & unknown
declare const symbol: unique symbol
/**
* Creates a branded type of `T` with the brand `U`.
*
* @example
* ```ts
* type Result = Branded<string, 'foo'>
* // ^? type Result = string & { [symbol]: 'foo' }
* ```
*/
export type Branded<T, U> = T & { [symbol]: U }
/**
* Filters out all members of `T` that are not `P`
*
* @example
* ```ts
* type Result = Filter<['a', 'b', 'c'], 'b'>
* // ^? type Result = ['a', 'c']
* ```
*
* @internal
*/
export type Filter<
T extends readonly unknown[],
P,
Acc extends readonly unknown[] = [],
> = T extends readonly [infer F, ...infer Rest extends readonly unknown[]]
? [F] extends [P]
? Filter<Rest, P, [...Acc, F]>
: Filter<Rest, P, Acc>
: readonly [...Acc]
/**
* Checks if `T` can be narrowed further than `U`
*
* @example
* ```ts
* type Result = IsNarrowable<'foo', string>
* // ^? true
* ```
*/
export type IsNarrowable<T, U> = IsNever<
(T extends U ? true : false) & (U extends T ? false : true)
> extends true
? false
: true
/**
* Checks if `T` is `never`
*
* @example
* ```ts
* type Result = IsNever<never>
* // ^? type Result = true
* ```
*/
export type IsNever<T> = [T] extends [never] ? true : false
/**
* Removes `readonly` from all properties of an object.
*
* @internal
*/
export type Mutable<type extends object> = {
-readonly [key in keyof type]: type[key]
}
/**
* Evaluates boolean "or" condition for `T` properties.
*
* * @example
* ```ts
* type Result = Or<[false, true, false]>
* // ^? type Result = true
* ```
*
* @example
* ```ts
* type Result = Or<[false, false, false]>
* // ^? type Result = false
* ```
*
* @internal
*/
export type Or<T extends readonly unknown[]> = T extends readonly [
infer Head,
...infer Tail,
]
? Head extends true
? true
: Or<Tail>
: false
/**
* Checks if `T` is `undefined`
*
* @example
* ```ts
* type Result = IsUndefined<undefined>
* // ^? type Result = true
* ```
*
* @internal
*/
export type IsUndefined<T> = [undefined] extends [T] ? true : false
/**
* Checks if type `T` is the `unknown` type.
*
* @internal
*/
export type IsUnknown<T> = unknown extends T
? [T] extends [null]
? false
: true
: false
/** @internal */
export type MaybePromise<T> = T | Promise<T>
/**
* Makes attributes on the type T required if required is true.
*
* @example
* ```ts
* MaybeRequired<{ a: string, b?: number }, true>
* // { a: string, b: number }
*
* MaybeRequired<{ a: string, b?: number }, false>
* // { a: string, b?: number }
* ```
*
* @internal
*/
export type MaybeRequired<T, required extends boolean> = required extends true
? ExactRequired<T>
: T
/**
* Assigns the properties of U onto T.
*
* @example
* ```ts
* Assign<{ a: string, b: number }, { a: undefined, c: boolean }>
* // { a: undefined, b: number, c: boolean }
* ```
*
* @internal
*/
export type Assign<T, U> = Assign_inner<T, U> & U
/** @internal */
export type Assign_inner<T, U> = {
[K in keyof T as K extends keyof U
? U[K] extends void
? never
: K
: K]: K extends keyof U ? U[K] : T[K]
}
/**
* Constructs a type by excluding `undefined` from `T`.
*
* @example
* ```ts
* NoUndefined<string | undefined>
* // string
* ```
*
* @internal
*/
export type NoUndefined<T> = T extends undefined ? never : T
/**
* Strict version of built-in Omit type
*
* @internal
*/
export type Omit<type, keys extends keyof type> = Pick<
type,
Exclude<keyof type, keys>
>
/**
* Creates a type that is a partial of T, but with the required keys K.
*
* @example
* ```ts
* PartialBy<{ a: string, b: number }, 'a'>
* // { a?: string, b: number }
* ```
*
* @internal
*/
export type PartialBy<T, K extends keyof T> = Omit<T, K> &
ExactPartial<Pick<T, K>>
export type RecursiveArray<T> = T | readonly RecursiveArray<T>[]
/**
* Creates a type that is T with the required keys K.
*
* @example
* ```ts
* RequiredBy<{ a?: string, b: number }, 'a'>
* // { a: string, b: number }
* ```
*
* @internal
*/
export type RequiredBy<T, K extends keyof T> = Omit<T, K> &
ExactRequired<Pick<T, K>>
/**
* Returns truthy if `array` contains `value`.
*
* @example
* ```ts
* Some<[1, 2, 3], 2>
* // true
* ```
*
* @internal
*/
export type Some<
array extends readonly unknown[],
value,
> = array extends readonly [value, ...unknown[]]
? true
: array extends readonly [unknown, ...infer rest]
? Some<rest, value>
: false
/**
* Prints custom error message
*
* @param messages - Error message
* @returns Custom error message
*
* @example
* ```ts
* type Result = TypeErrorMessage<'Custom error message'>
* // ^? type Result = ['Error: Custom error message']
* ```
*/
export type TypeErrorMessage<messages extends string | string[]> =
messages extends string
? [
// Surrounding with array to prevent `messages` from being widened to `string`
`Error: ${messages}`,
]
: {
[key in keyof messages]: messages[key] extends infer message extends
string
? `Error: ${message}`
: never
}
/** @internal */
export type UnionToTuple<
union,
///
last = LastInUnion<union>,
> = [union] extends [never] ? [] : [...UnionToTuple<Exclude<union, last>>, last]
/** @internal */
export type LastInUnion<U> = UnionToIntersection<
U extends unknown ? (x: U) => 0 : never
> extends (x: infer l) => 0
? l
: never
/** @internal */
export type UnionToIntersection<union> = (
union extends unknown
? (arg: union) => 0
: never
) extends (arg: infer i) => 0
? i
: never
/** @internal */
export type IsUnion<
union,
///
union2 = union,
> = union extends union2 ? ([union2] extends [union] ? false : true) : never
/** @internal */
export type MaybePartial<
type,
enabled extends boolean | undefined,
> = enabled extends true ? Compute<ExactPartial<type>> : type
export type ExactPartial<type> = {
[key in keyof type]?: type[key] | undefined
}
/** @internal */
export type ExactRequired<type> = {
[key in keyof type]-?: Exclude<type[key], undefined>
}
export type OneOf<
union extends object,
fallback extends object | undefined = undefined,
///
keys extends KeyofUnion<union> = KeyofUnion<union>,
> = union extends infer item
? Compute<
item & {
[key in Exclude<keys, keyof item>]?: fallback extends object
? key extends keyof fallback
? fallback[key]
: undefined
: undefined
}
>
: never
/** @internal */
export type KeyofUnion<type> = type extends type ? keyof type : never
/** @internal */
export type Undefined<type> = {
[key in keyof type]?: undefined
}
///////////////////////////////////////////////////////////////////////////
// Loose types
/**
* Loose version of {@link Omit}
* @internal
*/
export type LooseOmit<type, keys extends string> = Pick<
type,
Exclude<keyof type, keys>
>
///////////////////////////////////////////////////////////////////////////
// Union types
/** @internal */
export type UnionCompute<type> = type extends object ? Compute<type> : type
/** @internal */
export type UnionLooseOmit<type, keys extends string> = type extends any
? LooseOmit<type, keys>
: never
/**
* Construct a type with the properties of union type T except for those in type K.
* @example
* ```ts
* type Result = UnionOmit<{ a: string, b: number } | { a: string, b: undefined, c: number }, 'a'>
* // { b: number } | { b: undefined, c: number }
* ```
*
* @internal
*/
export type UnionOmit<type, keys extends keyof type> = type extends any
? Omit<type, keys>
: never
/**
* Construct a type with the properties of union type T except for those in type K.
* @example
* ```ts
* type Result = UnionOmit<{ a: string, b: number } | { a: string, b: undefined, c: number }, 'a'>
* // { b: number } | { b: undefined, c: number }
* ```
*
* @internal
*/
export type UnionPick<type, keys extends keyof type> = type extends any
? Pick<type, keys>
: never
/**
* Creates a type that is a partial of T, but with the required keys K.
*
* @example
* ```ts
* PartialBy<{ a: string, b: number } | { a: string, b: undefined, c: number }, 'a'>
* // { a?: string, b: number } | { a?: string, b: undefined, c: number }
* ```
*
* @internal
*/
export type UnionPartialBy<T, K extends keyof T> = T extends any
? PartialBy<T, K>
: never
/**
* Creates a type that is T with the required keys K.
*
* @example
* ```ts
* RequiredBy<{ a?: string, b: number } | { a?: string, c?: number }, 'a'>
* // { a: string, b: number } | { a: string, c?: number }
* ```
*
* @internal
*/
export type UnionRequiredBy<T, K extends keyof T> = T extends any
? RequiredBy<T, K>
: never