commitsmile
Version:
Make smile on your commits
1,899 lines (1,561 loc) • 59.9 kB
text/typescript
interface TextOptions {
message: string;
placeholder?: string;
defaultValue?: string;
initialValue?: string;
validate?: (value: string) => string | void;
}
declare const text: (opts: TextOptions) => Promise<string | symbol>;
interface ConfirmOptions {
message: string;
active?: string;
inactive?: string;
initialValue?: boolean;
}
declare const confirm: (opts: ConfirmOptions) => Promise<boolean | symbol>;
type Primitive$1 = Readonly<string | boolean | number>;
type Option<Value> = Value extends Primitive$1 ? {
value: Value;
label?: string;
hint?: string;
} : {
value: Value;
label: string;
hint?: string;
};
interface MultiSelectOptions<Value> {
message: string;
options: Option<Value>[];
initialValues?: Value[];
maxItems?: number;
required?: boolean;
cursorAt?: Value;
}
declare const multiselect: <Value>(opts: MultiSelectOptions<Value>) => Promise<symbol | Value[]>;
/** @dontexport TODO: TS-TOOLBELT COMPUTE WORK*/
type TSelectInput = FlatArray<Parameters<typeof multiselect>, 0> & {
/**
* How many custom values can be choosed?
* @default undefined
*/
custom?: number;
/**
* Allow to have multiple choice.
*/
multiple?: boolean;
};
/**
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
@category Type
*/
type Primitive =
| null
| undefined
| string
| number
| boolean
| symbol
| bigint;
declare global {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- It has to be an `interface` so that it can be merged.
interface SymbolConstructor {
readonly observable: symbol;
}
}
declare const emptyObjectSymbol: unique symbol;
/**
Represents a strictly empty plain object, the `{}` value.
When you annotate something as the type `{}`, it can be anything except `null` and `undefined`. This means that you cannot use `{}` to represent an empty plain object ([read more](https://stackoverflow.com/questions/47339869/typescript-empty-object-and-any-difference/52193484#52193484)).
@example
```
import type {EmptyObject} from 'type-fest';
// The following illustrates the problem with `{}`.
const foo1: {} = {}; // Pass
const foo2: {} = []; // Pass
const foo3: {} = 42; // Pass
const foo4: {} = {a: 1}; // Pass
// With `EmptyObject` only the first case is valid.
const bar1: EmptyObject = {}; // Pass
const bar2: EmptyObject = 42; // Fail
const bar3: EmptyObject = []; // Fail
const bar4: EmptyObject = {a: 1}; // Fail
```
Unfortunately, `Record<string, never>`, `Record<keyof any, never>` and `Record<never, never>` do not work. See {@link https://github.com/sindresorhus/type-fest/issues/395 #395}.
@category Object
*/
type EmptyObject = {[emptyObjectSymbol]?: never};
/**
Returns a boolean for whether the two given types are equal.
@link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
@link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796
Use-cases:
- If you want to make a conditional branch based on the result of a comparison of two types.
@example
```
import type {IsEqual} from 'type-fest';
// This type returns a boolean for whether the given array includes the given item.
// `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal.
type Includes<Value extends readonly any[], Item> =
Value extends readonly [Value[0], ...infer rest]
? IsEqual<Value[0], Item> extends true
? true
: Includes<rest, Item>
: false;
```
@category Type Guard
@category Utilities
*/
type IsEqual<A, B> =
(<G>() => G extends A ? 1 : 2) extends
(<G>() => G extends B ? 1 : 2)
? true
: false;
/**
Filter out keys from an object.
Returns `never` if `Exclude` is strictly equal to `Key`.
Returns `never` if `Key` extends `Exclude`.
Returns `Key` otherwise.
@example
```
type Filtered = Filter<'foo', 'foo'>;
//=> never
```
@example
```
type Filtered = Filter<'bar', string>;
//=> never
```
@example
```
type Filtered = Filter<'bar', 'foo'>;
//=> 'bar'
```
@see {Except}
*/
type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);
type ExceptOptions = {
/**
Disallow assigning non-specified properties.
Note that any omitted properties in the resulting type will be present in autocomplete as `undefined`.
@default false
*/
requireExactProps?: boolean;
};
/**
Create a type from an object type without certain keys.
We recommend setting the `requireExactProps` option to `true`.
This type is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). The `Omit` type does not restrict the omitted keys to be keys present on the given type, while `Except` does. The benefits of a stricter type are avoiding typos and allowing the compiler to pick up on rename refactors automatically.
This type was proposed to the TypeScript team, which declined it, saying they prefer that libraries implement stricter versions of the built-in types ([microsoft/TypeScript#30825](https://github.com/microsoft/TypeScript/issues/30825#issuecomment-523668235)).
@example
```
import type {Except} from 'type-fest';
type Foo = {
a: number;
b: string;
};
type FooWithoutA = Except<Foo, 'a'>;
//=> {b: string}
const fooWithoutA: FooWithoutA = {a: 1, b: '2'};
//=> errors: 'a' does not exist in type '{ b: string; }'
type FooWithoutB = Except<Foo, 'b', {requireExactProps: true}>;
//=> {a: number} & Partial<Record<"b", never>>
const fooWithoutB: FooWithoutB = {a: 1, b: '2'};
//=> errors at 'b': Type 'string' is not assignable to type 'undefined'.
```
@category Object
*/
type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {requireExactProps: false}> = {
[KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
} & (Options['requireExactProps'] extends true
? Partial<Record<KeysType, never>>
: {});
/**
Create a type that requires at least one of the given keys. The remaining keys are kept as is.
@example
```
import type {RequireAtLeastOne} from 'type-fest';
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
json: () => '{"message": "ok"}',
secure: true
};
```
@category Object
*/
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = {
// For each `Key` in `KeysType` make a mapped type:
[Key in KeysType]-?: Required<Pick<ObjectType, Key>> & // 1. Make `Key`'s type required
// 2. Make all other keys in `KeysType` optional
Partial<Pick<ObjectType, Exclude<KeysType, Key>>>;
}[KeysType] &
// 3. Add the remaining keys not in `KeysType`
Except<ObjectType, KeysType>;
/**
Represents an array with `unknown` value.
Use case: You want a type that all arrays can be assigned to, but you don't care about the value.
@example
```
import type {UnknownArray} from 'type-fest';
type IsArray<T> = T extends UnknownArray ? true : false;
type A = IsArray<['foo']>;
//=> true
type B = IsArray<readonly number[]>;
//=> true
type C = IsArray<string>;
//=> false
```
@category Type
@category Array
*/
type UnknownArray = readonly unknown[];
/**
Returns the static, fixed-length portion of the given array, excluding variable-length parts.
@example
```
type A = [string, number, boolean, ...string[]];
type B = StaticPartOfArray<A>;
//=> [string, number, boolean]
```
*/
type StaticPartOfArray<T extends UnknownArray, Result extends UnknownArray = []> =
T extends unknown
? number extends T['length'] ?
T extends readonly [infer U, ...infer V]
? StaticPartOfArray<V, [...Result, U]>
: Result
: T
: never; // Should never happen
/**
Returns the variable, non-fixed-length portion of the given array, excluding static-length parts.
@example
```
type A = [string, number, boolean, ...string[]];
type B = VariablePartOfArray<A>;
//=> string[]
```
*/
type VariablePartOfArray<T extends UnknownArray> =
T extends unknown
? T extends readonly [...StaticPartOfArray<T>, ...infer U]
? U
: []
: never; // Should never happen
/**
Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
@example
```
type ReadonlyArray = readonly string[];
type NormalArray = string[];
type ReadonlyResult = SetArrayAccess<NormalArray, true>;
//=> readonly string[]
type NormalResult = SetArrayAccess<ReadonlyArray, false>;
//=> string[]
```
*/
type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
T extends readonly [...infer U] ?
IsReadonly extends true
? readonly [...U]
: [...U]
: T;
/**
Returns whether the given array `T` is readonly.
*/
type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
// Can eventually be replaced with the built-in once this library supports
// TS5.4+ only. Tracked in https://github.com/sindresorhus/type-fest/issues/848
type NoInfer<T> = T extends infer U ? U : never;
/**
Returns a boolean for whether the given type is `any`.
@link https://stackoverflow.com/a/49928360/1490091
Useful in type utilities, such as disallowing `any`s to be passed to a function.
@example
```
import type {IsAny} from 'type-fest';
const typedObject = {a: 1, b: 2} as const;
const anyObject: any = {a: 1, b: 2};
function get<O extends (IsAny<O> extends true ? {} : Record<string, number>), K extends keyof O = keyof O>(obj: O, key: K) {
return obj[key];
}
const typedA = get(typedObject, 'a');
//=> 1
const anyA = get(anyObject, 'a');
//=> any
```
@category Type Guard
@category Utilities
*/
type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
type Numeric = number | bigint;
type Zero = 0 | 0n;
/**
Matches the hidden `Infinity` type.
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/32277) if you want to have this type as a built-in in TypeScript.
@see NegativeInfinity
@category Numeric
*/
// See https://github.com/microsoft/TypeScript/issues/31752
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
type PositiveInfinity = 1e999;
/**
Matches the hidden `-Infinity` type.
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/32277) if you want to have this type as a built-in in TypeScript.
@see PositiveInfinity
@category Numeric
*/
// See https://github.com/microsoft/TypeScript/issues/31752
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
type NegativeInfinity = -1e999;
/**
A negative `number`/`bigint` (`-∞ < x < 0`)
Use-case: Validating and documenting parameters.
@see NegativeInteger
@see NonNegative
@category Numeric
*/
type Negative<T extends Numeric> = T extends Zero ? never : `${T}` extends `-${string}` ? T : never;
/**
Returns a boolean for whether the given number is a negative number.
@see Negative
@example
```
import type {IsNegative} from 'type-fest';
type ShouldBeFalse = IsNegative<1>;
type ShouldBeTrue = IsNegative<-1>;
```
@category Numeric
*/
type IsNegative<T extends Numeric> = T extends Negative<T> ? true : false;
/**
Returns a boolean for whether the given type is `never`.
@link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
@link https://stackoverflow.com/a/53984913/10292952
@link https://www.zhenghao.io/posts/ts-never
Useful in type utilities, such as checking if something does not occur.
@example
```
import type {IsNever, And} from 'type-fest';
// https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
type AreStringsEqual<A extends string, B extends string> =
And<
IsNever<Exclude<A, B>> extends true ? true : false,
IsNever<Exclude<B, A>> extends true ? true : false
>;
type EndIfEqual<I extends string, O extends string> =
AreStringsEqual<I, O> extends true
? never
: void;
function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
if (input === output) {
process.exit(0);
}
}
endIfEqual('abc', 'abc');
//=> never
endIfEqual('abc', '123');
//=> void
```
@category Type Guard
@category Utilities
*/
type IsNever<T> = [T] extends [never] ? true : false;
/**
Returns a boolean for whether two given types are both true.
Use-case: Constructing complex conditional types where multiple conditions must be satisfied.
@example
```
import type {And} from 'type-fest';
And<true, true>;
//=> true
And<true, false>;
//=> false
```
@see {@link Or}
*/
type And<A extends boolean, B extends boolean> = [A, B][number] extends true
? true
: true extends [IsEqual<A, false>, IsEqual<B, false>][number]
? false
: never;
/**
Returns a boolean for whether either of two given types are true.
Use-case: Constructing complex conditional types where multiple conditions must be satisfied.
@example
```
import type {Or} from 'type-fest';
Or<true, false>;
//=> true
Or<false, false>;
//=> false
```
@see {@link And}
*/
type Or<A extends boolean, B extends boolean> = [A, B][number] extends false
? false
: true extends [IsEqual<A, true>, IsEqual<B, true>][number]
? true
: never;
/**
Returns a boolean for whether a given number is greater than another number.
@example
```
import type {GreaterThan} from 'type-fest';
GreaterThan<1, -5>;
//=> true
GreaterThan<1, 1>;
//=> false
GreaterThan<1, 5>;
//=> false
```
*/
type GreaterThan<A extends number, B extends number> = number extends A | B
? never
: [
IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
] extends infer R extends [boolean, boolean, boolean, boolean]
? Or<
And<IsEqual<R[0], true>, IsEqual<R[2], false>>,
And<IsEqual<R[3], true>, IsEqual<R[1], false>>
> extends true
? true
: Or<
And<IsEqual<R[1], true>, IsEqual<R[3], false>>,
And<IsEqual<R[2], true>, IsEqual<R[0], false>>
> extends true
? false
: true extends R[number]
? false
: [IsNegative<A>, IsNegative<B>] extends infer R extends [boolean, boolean]
? [true, false] extends R
? false
: [false, true] extends R
? true
: [false, false] extends R
? PositiveNumericStringGt<`${A}`, `${B}`>
: PositiveNumericStringGt<`${NumberAbsolute<B>}`, `${NumberAbsolute<A>}`>
: never
: never;
/**
Returns a boolean for whether a given number is greater than or equal to another number.
@example
```
import type {GreaterThanOrEqual} from 'type-fest';
GreaterThanOrEqual<1, -5>;
//=> true
GreaterThanOrEqual<1, 1>;
//=> true
GreaterThanOrEqual<1, 5>;
//=> false
```
*/
type GreaterThanOrEqual<A extends number, B extends number> = number extends A | B
? never
: A extends B ? true : GreaterThan<A, B>;
/**
Returns a boolean for whether a given number is less than another number.
@example
```
import type {LessThan} from 'type-fest';
LessThan<1, -5>;
//=> false
LessThan<1, 1>;
//=> false
LessThan<1, 5>;
//=> true
```
*/
type LessThan<A extends number, B extends number> = number extends A | B
? never
: GreaterThanOrEqual<A, B> extends true ? false : true;
/**
Infer the length of the given tuple `<T>`.
Returns `never` if the given type is an non-fixed-length array like `Array<string>`.
@example
```
type Tuple = TupleLength<[string, number, boolean]>;
//=> 3
type Array = TupleLength<string[]>;
//=> never
// Supports union types.
type Union = TupleLength<[] | [1, 2, 3] | Array<number>>;
//=> 1 | 3
```
*/
type TupleLength<T extends UnknownArray> =
// `extends unknown` is used to convert `T` (if `T` is a union type) to
// a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types))
T extends unknown
? number extends T['length']
? never // Return never if the given type is an non-flexed-length array like `Array<string>`
: T['length']
: never; // Should never happen
/**
Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
If `<Fill>` is not provided, it will default to `unknown`.
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
*/
type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = []> = T['length'] extends L
? T
: BuildTuple<L, Fill, [...T, Fill]>;
/**
Returns the maximum value from a tuple of integers.
Note:
- Float numbers are not supported.
@example
```
ArrayMax<[1, 2, 5, 3]>;
//=> 5
ArrayMax<[1, 2, 5, 3, 99, -1]>;
//=> 99
```
*/
type TupleMax<A extends number[], Result extends number = NegativeInfinity> = number extends A[number]
? never :
A extends [infer F extends number, ...infer R extends number[]]
? GreaterThan<F, Result> extends true
? TupleMax<R, F>
: TupleMax<R, Result>
: Result;
/**
Returns the minimum value from a tuple of integers.
Note:
- Float numbers are not supported.
@example
```
ArrayMin<[1, 2, 5, 3]>;
//=> 1
ArrayMin<[1, 2, 5, 3, -5]>;
//=> -5
```
*/
type TupleMin<A extends number[], Result extends number = PositiveInfinity> = number extends A[number]
? never
: A extends [infer F extends number, ...infer R extends number[]]
? LessThan<F, Result> extends true
? TupleMin<R, F>
: TupleMin<R, Result>
: Result;
/**
Return a string representation of the given string or number.
Note: This type is not the return type of the `.toString()` function.
*/
type ToString<T> = T extends string | number ? `${T}` : never;
/**
Converts a numeric string to a number.
@example
```
type PositiveInt = StringToNumber<'1234'>;
//=> 1234
type NegativeInt = StringToNumber<'-1234'>;
//=> -1234
type PositiveFloat = StringToNumber<'1234.56'>;
//=> 1234.56
type NegativeFloat = StringToNumber<'-1234.56'>;
//=> -1234.56
type PositiveInfinity = StringToNumber<'Infinity'>;
//=> Infinity
type NegativeInfinity = StringToNumber<'-Infinity'>;
//=> -Infinity
```
@category String
@category Numeric
@category Template literal
*/
type StringToNumber<S extends string> = S extends `${infer N extends number}`
? N
: S extends 'Infinity'
? PositiveInfinity
: S extends '-Infinity'
? NegativeInfinity
: never;
/**
Returns an array of the characters of the string.
@example
```
StringToArray<'abcde'>;
//=> ['a', 'b', 'c', 'd', 'e']
StringToArray<string>;
//=> never
```
@category String
*/
type StringToArray<S extends string, Result extends string[] = []> = string extends S
? never
: S extends `${infer F}${infer R}`
? StringToArray<R, [...Result, F]>
: Result;
/**
Returns the length of the given string.
@example
```
StringLength<'abcde'>;
//=> 5
StringLength<string>;
//=> never
```
@category String
@category Template literal
*/
type StringLength<S extends string> = string extends S
? never
: StringToArray<S>['length'];
/**
Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both numeric strings and have the same length.
@example
```
SameLengthPositiveNumericStringGt<'50', '10'>;
//=> true
SameLengthPositiveNumericStringGt<'10', '10'>;
//=> false
```
*/
type SameLengthPositiveNumericStringGt<A extends string, B extends string> = A extends `${infer FirstA}${infer RestA}`
? B extends `${infer FirstB}${infer RestB}`
? FirstA extends FirstB
? SameLengthPositiveNumericStringGt<RestA, RestB>
: PositiveNumericCharacterGt<FirstA, FirstB>
: never
: false;
type NumericString = '0123456789';
/**
Returns a boolean for whether `A` is greater than `B`, where `A` and `B` are both positive numeric strings.
@example
```
PositiveNumericStringGt<'500', '1'>;
//=> true
PositiveNumericStringGt<'1', '1'>;
//=> false
PositiveNumericStringGt<'1', '500'>;
//=> false
```
*/
type PositiveNumericStringGt<A extends string, B extends string> = A extends B
? false
: [BuildTuple<StringLength<A>, 0>, BuildTuple<StringLength<B>, 0>] extends infer R extends [readonly unknown[], readonly unknown[]]
? R[0] extends [...R[1], ...infer Remain extends readonly unknown[]]
? 0 extends Remain['length']
? SameLengthPositiveNumericStringGt<A, B>
: true
: false
: never;
/**
Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both positive numeric characters.
@example
```
PositiveNumericCharacterGt<'5', '1'>;
//=> true
PositiveNumericCharacterGt<'1', '1'>;
//=> false
```
*/
type PositiveNumericCharacterGt<A extends string, B extends string> = NumericString extends `${infer HeadA}${A}${infer TailA}`
? NumericString extends `${infer HeadB}${B}${infer TailB}`
? HeadA extends `${HeadB}${infer _}${infer __}`
? true
: false
: never
: never;
/**
Get the exact version of the given `Key` in the given object `T`.
Use-case: You known that a number key (e.g. 10) is in an object, but you don't know how it is defined in the object, as a string or as a number (e.g. 10 or '10'). You can use this type to get the exact version of the key. See the example.
@example
```
type Object = {
0: number;
'1': string;
};
type Key1 = ExactKey<Object, '0'>;
//=> 0
type Key2 = ExactKey<Object, 0>;
//=> 0
type Key3 = ExactKey<Object, '1'>;
//=> '1'
type Key4 = ExactKey<Object, 1>;
//=> '1'
```
@category Object
*/
type ExactKey<T extends object, Key extends PropertyKey> =
Key extends keyof T
? Key
: ToString<Key> extends keyof T
? ToString<Key>
: Key extends `${infer NumberKey extends number}`
? NumberKey extends keyof T
? NumberKey
: never
: never;
/**
Returns the absolute value of a given value.
@example
```
NumberAbsolute<-1>;
//=> 1
NumberAbsolute<1>;
//=> 1
NumberAbsolute<NegativeInfinity>
//=> PositiveInfinity
```
*/
type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
/**
Check whether the given type is a number or a number string.
Supports floating-point as a string.
@example
```
type A = IsNumberLike<'1'>;
//=> true
type B = IsNumberLike<'-1.1'>;
//=> true
type C = IsNumberLike<1>;
//=> true
type D = IsNumberLike<'a'>;
//=> false
*/
type IsNumberLike<N> =
N extends number ? true
: N extends `${number}`
? true
: N extends `${number}.${number}`
? true
: false;
/**
Returns the minimum number in the given union of numbers.
Note: Just supports numbers from 0 to 999.
@example
```
type A = UnionMin<3 | 1 | 2>;
//=> 1
```
*/
type UnionMin<N extends number> = InternalUnionMin<N>;
/**
The actual implementation of `UnionMin`. It's private because it has some arguments that don't need to be exposed.
*/
type InternalUnionMin<N extends number, T extends UnknownArray = []> =
T['length'] extends N
? T['length']
: InternalUnionMin<N, [...T, unknown]>;
/**
Returns the maximum number in the given union of numbers.
Note: Just supports numbers from 0 to 999.
@example
```
type A = UnionMax<1 | 3 | 2>;
//=> 3
```
*/
type UnionMax<N extends number> = InternalUnionMax<N>;
/**
The actual implementation of `UnionMax`. It's private because it has some arguments that don't need to be exposed.
*/
type InternalUnionMax<N extends number, T extends UnknownArray = []> =
IsNever<N> extends true
? T['length']
: T['length'] extends N
? InternalUnionMax<Exclude<N, T['length']>, T>
: InternalUnionMax<N, [...T, unknown]>;
/**
Matches any primitive, `void`, `Date`, or `RegExp` value.
*/
type BuiltIns = Primitive | void | Date | RegExp;
/**
Matches non-recursive types.
*/
type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
/**
Recursively simplifies a type while including and/or excluding certain types from being simplified.
This type is **experimental** and was introduced as a result of this {@link https://github.com/sindresorhus/type-fest/issues/436 issue}. It should be used with caution.
See {@link ConditionalSimplify} for usages and examples.
@internal
@experimental
@category Object
*/
type ConditionalSimplifyDeep<Type, ExcludeType = never, IncludeType = unknown> = Type extends ExcludeType
? Type
: Type extends IncludeType
? {[TypeKey in keyof Type]: ConditionalSimplifyDeep<Type[TypeKey], ExcludeType, IncludeType>}
: Type;
/**
Deeply simplifies an object type.
You can exclude certain types from being simplified by providing them in the second generic `ExcludeType`.
Useful to flatten the type output to improve type hints shown in editors.
@example
```
import type {SimplifyDeep} from 'type-fest';
type PositionX = {
left: number;
right: number;
};
type PositionY = {
top: number;
bottom: number;
};
type Properties1 = {
height: number;
position: PositionY;
};
type Properties2 = {
width: number;
position: PositionX;
};
type Properties = Properties1 & Properties2;
// In your editor, hovering over `Props` will show the following:
//
// type Properties = Properties1 & Properties2;
type SimplifyDeepProperties = SimplifyDeep<Properties1 & Properties2>;
// But if wrapped in SimplifyDeep, hovering over `SimplifyDeepProperties` will show a flattened object with all the properties:
//
// SimplifyDeepProperties = {
// height: number;
// width: number;
// position: {
// top: number;
// bottom: number;
// left: number;
// right: number;
// };
// };
```
@example
```
import type {SimplifyDeep} from 'type-fest';
// A complex type that you don't want or need to simplify
type ComplexType = {
a: string;
b: 'b';
c: number;
...
};
type PositionX = {
left: number;
right: number;
};
type PositionY = {
top: number;
bottom: number;
};
// You want to simplify all other types
type Properties1 = {
height: number;
position: PositionY;
foo: ComplexType;
};
type Properties2 = {
width: number;
position: PositionX;
foo: ComplexType;
};
type SimplifyDeepProperties = SimplifyDeep<Properties1 & Properties2, ComplexType>;
// If wrapped in `SimplifyDeep` and set `ComplexType` to exclude, hovering over `SimplifyDeepProperties` will
// show a flattened object with all the properties except `ComplexType`:
//
// SimplifyDeepProperties = {
// height: number;
// width: number;
// position: {
// top: number;
// bottom: number;
// left: number;
// right: number;
// };
// foo: ComplexType;
// };
```
@see Simplify
@category Object
*/
type SimplifyDeep<Type, ExcludeType = never> =
ConditionalSimplifyDeep<
Type,
ExcludeType | NonRecursiveType | Set<unknown> | Map<unknown, unknown>,
object
>;
/**
@see PartialDeep
*/
type PartialDeepOptions = {
/**
Whether to affect the individual elements of arrays and tuples.
@default false
*/
readonly recurseIntoArrays?: boolean;
};
/**
Create a type from another type with all keys and nested keys set to optional.
Use-cases:
- Merging a default settings/config object with another object, the second object would be a deep partial of the default object.
- Mocking and testing complex entities, where populating an entire object with its keys would be redundant in terms of the mock or test.
@example
```
import type {PartialDeep} from 'type-fest';
const settings: Settings = {
textEditor: {
fontSize: 14;
fontColor: '#000000';
fontWeight: 400;
}
autocomplete: false;
autosave: true;
};
const applySavedSettings = (savedSettings: PartialDeep<Settings>) => {
return {...settings, ...savedSettings};
}
settings = applySavedSettings({textEditor: {fontWeight: 500}});
```
By default, this does not affect elements in array and tuple types. You can change this by passing `{recurseIntoArrays: true}` as the second type argument:
```
import type {PartialDeep} from 'type-fest';
interface Settings {
languages: string[];
}
const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
languages: [undefined]
};
```
@category Object
@category Array
@category Set
@category Map
*/
type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns | (((...arguments_: any[]) => unknown)) | (new (...arguments_: any[]) => unknown)
? T
: T extends Map<infer KeyType, infer ValueType>
? PartialMapDeep<KeyType, ValueType, Options>
: T extends Set<infer ItemType>
? PartialSetDeep<ItemType, Options>
: T extends ReadonlyMap<infer KeyType, infer ValueType>
? PartialReadonlyMapDeep<KeyType, ValueType, Options>
: T extends ReadonlySet<infer ItemType>
? PartialReadonlySetDeep<ItemType, Options>
: T extends object
? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
? Options['recurseIntoArrays'] extends true
? ItemType[] extends T // Test for arrays (non-tuples) specifically
? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
: Array<PartialDeep<ItemType | undefined, Options>>
: PartialObjectDeep<T, Options> // Tuples behave properly
: T // If they don't opt into array testing, just use the original type
: PartialObjectDeep<T, Options>
: unknown;
/**
Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
*/
type PartialMapDeep<KeyType, ValueType, Options extends PartialDeepOptions> = {} & Map<PartialDeep<KeyType, Options>, PartialDeep<ValueType, Options>>;
/**
Same as `PartialDeep`, but accepts only `Set`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialSetDeep<T, Options extends PartialDeepOptions> = {} & Set<PartialDeep<T, Options>>;
/**
Same as `PartialDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialReadonlyMapDeep<KeyType, ValueType, Options extends PartialDeepOptions> = {} & ReadonlyMap<PartialDeep<KeyType, Options>, PartialDeep<ValueType, Options>>;
/**
Same as `PartialDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialReadonlySetDeep<T, Options extends PartialDeepOptions> = {} & ReadonlySet<PartialDeep<T, Options>>;
/**
Same as `PartialDeep`, but accepts only `object`s as inputs. Internal helper for `PartialDeep`.
*/
type PartialObjectDeep<ObjectType extends object, Options extends PartialDeepOptions> = {
[KeyType in keyof ObjectType]?: PartialDeep<ObjectType[KeyType], Options>
};
/**
Returns the sum of two numbers.
Note:
- A or B can only support `-999` ~ `999`.
- A and B can only be small integers, less than 1000.
- If the result is negative, you can only get `number`.
@example
```
import type {Sum} from 'type-fest';
Sum<111, 222>;
//=> 333
Sum<-111, 222>;
//=> 111
Sum<111, -222>;
//=> number
Sum<PositiveInfinity, -9999>;
//=> PositiveInfinity
Sum<PositiveInfinity, NegativeInfinity>;
//=> number
```
@category Numeric
*/
// TODO: Support big integer and negative number.
type Sum<A extends number, B extends number> = number extends A | B
? number
: [
IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
] extends infer R extends [boolean, boolean, boolean, boolean]
? Or<
And<IsEqual<R[0], true>, IsEqual<R[3], false>>,
And<IsEqual<R[2], true>, IsEqual<R[1], false>>
> extends true
? PositiveInfinity
: Or<
And<IsEqual<R[1], true>, IsEqual<R[2], false>>,
And<IsEqual<R[3], true>, IsEqual<R[0], false>>
> extends true
? NegativeInfinity
: true extends R[number]
? number
: ([IsNegative<A>, IsNegative<B>] extends infer R
? [false, false] extends R
? [...BuildTuple<A>, ...BuildTuple<B>]['length']
: [true, true] extends R
? number
: TupleMax<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Max_
? TupleMin<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Min_ extends number
? Max_ extends A | B
? Subtract<Max_, Min_>
: number
: never
: never
: never) & number
: never;
/**
Returns the difference between two numbers.
Note:
- A or B can only support `-999` ~ `999`.
- If the result is negative, you can only get `number`.
@example
```
import type {Subtract} from 'type-fest';
Subtract<333, 222>;
//=> 111
Subtract<111, -222>;
//=> 333
Subtract<-111, 222>;
//=> number
Subtract<PositiveInfinity, 9999>;
//=> PositiveInfinity
Subtract<PositiveInfinity, PositiveInfinity>;
//=> number
```
@category Numeric
*/
// TODO: Support big integer and negative number.
type Subtract<A extends number, B extends number> = number extends A | B
? number
: [
IsEqual<A, PositiveInfinity>, IsEqual<A, NegativeInfinity>,
IsEqual<B, PositiveInfinity>, IsEqual<B, NegativeInfinity>,
] extends infer R extends [boolean, boolean, boolean, boolean]
? Or<
And<IsEqual<R[0], true>, IsEqual<R[2], false>>,
And<IsEqual<R[3], true>, IsEqual<R[1], false>>
> extends true
? PositiveInfinity
: Or<
And<IsEqual<R[1], true>, IsEqual<R[3], false>>,
And<IsEqual<R[2], true>, IsEqual<R[0], false>>
> extends true
? NegativeInfinity
: true extends R[number]
? number
: [IsNegative<A>, IsNegative<B>] extends infer R
? [false, false] extends R
? BuildTuple<A> extends infer R
? R extends [...BuildTuple<B>, ...infer R]
? R['length']
: number
: never
: LessThan<A, B> extends true
? number
: [false, true] extends R
? Sum<A, NumberAbsolute<B>>
: Subtract<NumberAbsolute<B>, NumberAbsolute<A>>
: never
: never;
/**
Paths options.
@see {@link Paths}
*/
type PathsOptions = {
/**
The maximum depth to recurse when searching for paths.
@default 10
*/
maxRecursionDepth?: number;
/**
Use bracket notation for array indices and numeric object keys.
@default false
@example
```
type ArrayExample = {
array: ['foo'];
};
type A = Paths<ArrayExample, {bracketNotation: false}>;
//=> 'array' | 'array.0'
type B = Paths<ArrayExample, {bracketNotation: true}>;
//=> 'array' | 'array[0]'
```
@example
```
type NumberKeyExample = {
1: ['foo'];
};
type A = Paths<NumberKeyExample, {bracketNotation: false}>;
//=> 1 | '1' | '1.0'
type B = Paths<NumberKeyExample, {bracketNotation: true}>;
//=> '[1]' | '[1][0]'
```
*/
bracketNotation?: boolean;
};
type DefaultPathsOptions = {
maxRecursionDepth: 10;
bracketNotation: false;
};
/**
Generate a union of all possible paths to properties in the given object.
It also works with arrays.
Use-case: You want a type-safe way to access deeply nested properties in an object.
@example
```
import type {Paths} from 'type-fest';
type Project = {
filename: string;
listA: string[];
listB: [{filename: string}];
folder: {
subfolder: {
filename: string;
};
};
};
type ProjectPaths = Paths<Project>;
//=> 'filename' | 'listA' | 'listB' | 'folder' | `listA.${number}` | 'listB.0' | 'listB.0.filename' | 'folder.subfolder' | 'folder.subfolder.filename'
declare function open<Path extends ProjectPaths>(path: Path): void;
open('filename'); // Pass
open('folder.subfolder'); // Pass
open('folder.subfolder.filename'); // Pass
open('foo'); // TypeError
// Also works with arrays
open('listA.1'); // Pass
open('listB.0'); // Pass
open('listB.1'); // TypeError. Because listB only has one element.
```
@category Object
@category Array
*/
type Paths<T, Options extends PathsOptions = {}> = _Paths<T, {
// Set default maxRecursionDepth to 10
maxRecursionDepth: Options['maxRecursionDepth'] extends number ? Options['maxRecursionDepth'] : DefaultPathsOptions['maxRecursionDepth'];
// Set default bracketNotation to false
bracketNotation: Options['bracketNotation'] extends boolean ? Options['bracketNotation'] : DefaultPathsOptions['bracketNotation'];
}>;
type _Paths<T, Options extends Required<PathsOptions>> =
T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
? never
: IsAny<T> extends true
? never
: T extends UnknownArray
? number extends T['length']
// We need to handle the fixed and non-fixed index part of the array separately.
? InternalPaths<StaticPartOfArray<T>, Options>
| InternalPaths<Array<VariablePartOfArray<T>[number]>, Options>
: InternalPaths<T, Options>
: T extends object
? InternalPaths<T, Options>
: never;
type InternalPaths<T, Options extends Required<PathsOptions>> =
Options['maxRecursionDepth'] extends infer MaxDepth extends number
? Required<T> extends infer T
? T extends EmptyObject | readonly []
? never
: {
[Key in keyof T]:
Key extends string | number // Limit `Key` to string or number.
? (
Options['bracketNotation'] extends true
? IsNumberLike<Key> extends true
? `[${Key}]`
: (Key | ToString<Key>)
: never
|
Options['bracketNotation'] extends false
// If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
? (Key | ToString<Key>)
: never
) extends infer TranformedKey extends string | number ?
// 1. If style is 'a[0].b' and 'Key' is a numberlike value like 3 or '3', transform 'Key' to `[${Key}]`, else to `${Key}` | Key
// 2. If style is 'a.0.b', transform 'Key' to `${Key}` | Key
| TranformedKey
| (
// Recursively generate paths for the current key
GreaterThan<MaxDepth, 0> extends true // Limit the depth to prevent infinite recursion
? _Paths<T[Key], {bracketNotation: Options['bracketNotation']; maxRecursionDepth: Subtract<MaxDepth, 1>}> extends infer SubPath
? SubPath extends string | number
? (
Options['bracketNotation'] extends true
? SubPath extends `[${any}]` | `[${any}]${string}`
? `${TranformedKey}${SubPath}` // If next node is number key like `[3]`, no need to add `.` before it.
: `${TranformedKey}.${SubPath}`
: never
) | (
Options['bracketNotation'] extends false
? `${TranformedKey}.${SubPath}`
: never
)
: never
: never
: never
)
: never
: never
}[keyof T & (T extends UnknownArray ? number : unknown)]
: never
: never;
/**
The implementation of `SplitArrayByIndex` for fixed length arrays.
*/
type SplitFixedArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
SplitIndex extends 0
? [[], T]
: T extends readonly [...BuildTuple<SplitIndex>, ...infer V]
? T extends readonly [...infer U, ...V]
? [U, V]
: [never, never]
: [never, never];
/**
The implementation of `SplitArrayByIndex` for variable length arrays.
*/
type SplitVariableArrayByIndex<T extends UnknownArray,
SplitIndex extends number,
T1 = Subtract<SplitIndex, StaticPartOfArray<T>['length']>,
T2 = T1 extends number ? BuildTuple<T1, VariablePartOfArray<T>[number]> : [],
> =
SplitIndex extends 0
? [[], T]
: GreaterThanOrEqual<StaticPartOfArray<T>['length'], SplitIndex> extends true
? [
SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[0],
[
...SplitFixedArrayByIndex<StaticPartOfArray<T>, SplitIndex>[1],
...VariablePartOfArray<T>,
],
]
: [
[
...StaticPartOfArray<T>,
...(T2 extends UnknownArray ? T2 : []),
],
VariablePartOfArray<T>,
];
/**
Split the given array `T` by the given `SplitIndex`.
@example
```
type A = SplitArrayByIndex<[1, 2, 3, 4], 2>;
// type A = [[1, 2], [3, 4]];
type B = SplitArrayByIndex<[1, 2, 3, 4], 0>;
// type B = [[], [1, 2, 3, 4]];
```
*/
type SplitArrayByIndex<T extends UnknownArray, SplitIndex extends number> =
SplitIndex extends 0
? [[], T]
: number extends T['length']
? SplitVariableArrayByIndex<T, SplitIndex>
: SplitFixedArrayByIndex<T, SplitIndex>;
/**
Creates a new array type by adding or removing elements at a specified index range in the original array.
Use-case: Replace or insert items in an array type.
Like [`Array#splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) but for types.
@example
```
type SomeMonths0 = ['January', 'April', 'June'];
type Mouths0 = ArraySplice<SomeMonths0, 1, 0, ['Feb', 'March']>;
//=> type Mouths0 = ['January', 'Feb', 'March', 'April', 'June'];
type SomeMonths1 = ['January', 'April', 'June'];
type Mouths1 = ArraySplice<SomeMonths1, 1, 1>;
//=> type Mouths1 = ['January', 'June'];
type SomeMonths2 = ['January', 'Foo', 'April'];
type Mouths2 = ArraySplice<SomeMonths2, 1, 1, ['Feb', 'March']>;
//=> type Mouths2 = ['January', 'Feb', 'March', 'April'];
```
@category Array
*/
type ArraySplice<
T extends UnknownArray,
Start extends number,
DeleteCount extends number,
Items extends UnknownArray = [],
> =
SplitArrayByIndex<T, Start> extends [infer U extends UnknownArray, infer V extends UnknownArray]
? SplitArrayByIndex<V, DeleteCount> extends [infer _Deleted extends UnknownArray, infer X extends UnknownArray]
? [...U, ...Items, ...X]
: never // Should never happen
: never; // Should never happen
/**
Allows creating a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union.
Currently, when a union type of a primitive type is combined with literal types, TypeScript loses all information about the combined literals. Thus, when such type is used in an IDE with autocompletion, no suggestions are made for the declared literals.
This type is a workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). It will be removed as soon as it's not needed anymore.
@example
```
import type {LiteralUnion} from 'type-fest';
// Before
type Pet = 'dog' | 'cat' | string;
const pet: Pet = '';
// Start typing in your TypeScript-enabled IDE.
// You **will not** get auto-completion for `dog` and `cat` literals.
// After
type Pet2 = LiteralUnion<'dog' | 'cat', string>;
const pet: Pet2 = '';
// You **will** get auto-completion for `dog` and `cat` literals.
```
@category Type
*/
type LiteralUnion<
LiteralType,
BaseType extends Primitive,
> = LiteralType | (BaseType & Record<never, never>);
/**
SharedUnionFieldsDeep options.
@see {@link SharedUnionFieldsDeep}
*/
type SharedUnionFieldsDeepOptions = {
/**
When set to true, this option impacts each element within arrays or tuples. If all union values are arrays or tuples, it constructs an array of the shortest possible length, ensuring every element exists in the union array.
@default false
*/
recurseIntoArrays?: boolean;
};
/**
Create a type with shared fields from a union of object types, deeply traversing nested structures.
Use the {@link SharedUnionFieldsDeepOptions `Options`} to specify the behavior for arrays.
Use-cases:
- You want a safe object type where each key exists in the union object.
- You want to focus on the common fields of the union type and don't want to have to care about the other fields.
@example
```
import type {SharedUnionFieldsDeep} from 'type-fest';
type Cat = {
info: {
name: string;
type: 'cat';
catType: string;
};
};
type Dog = {
info: {
name: string;
type: 'dog';
dogType: string;
};
};
function displayPetInfo(petInfo: (Cat | Dog)['info']) {
// typeof petInfo =>
// {
// name: string;
// type: 'cat';
// catType: string; // Needn't care about this field, because it's not a common pet info field.
// } | {
// name: string;
// type: 'dog';
// dogType: string; // Needn't care about this field, because it's not a common pet info field.
// }
// petInfo type is complex and have some needless fields
console.log('name: ', petInfo.name);
console.log('type: ', petInfo.type);
}
function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
// typeof petInfo =>
// {
// name: string;
// type: 'cat' | 'dog';
// }
// petInfo type is simple and clear
console.log('name: ', petInfo.name);
console.log('type: ', petInfo.type);
}
```
@see SharedUnionFields
@category Object
@category Union
*/
type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {recurseIntoArrays: false}> =
// `Union extends` will convert `Union`
// to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
// But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
[Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
? Union
: [Union] extends [UnknownArray]
? Options['recurseIntoArrays'] extends true
? SetArrayAccess<SharedArrayUnionFieldsDeep<Union, Options>, IsArrayReadonly<Union>>
: Union
: [Union] extends [object]
? SharedObjectUnionFieldsDeep<Union, Options>
: Union;
/**
Same as `SharedUnionFieldsDeep`, but accepts only `object`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
*/
type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions> =
// `keyof Union` can extract the same key in union type, if there is no same key, return never.
keyof Union extends infer Keys
? IsNever<Keys> extends false
? {
[Key in keyof Union]:
Union[Key] extends NonRecursiveType
? Union[Key]
// Remove `undefined` from the union to support optional
// fields, then recover `undefined` if union was already undefined.
: SharedUnionFieldsDeep<Exclude<Union[Key], undefined>, Options> | (
undefined extends Required<Union>[Key] ? undefined : never
)
}
: {}
: Union;
/**
Same as `SharedUnionFieldsDeep`, but accepts only `UnknownArray`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
*/
type SharedArrayUnionFieldsDeep<Union extends UnknownArray, Options extends SharedUnionFieldsDeepOptions> =
// Restore the readonly modifier of the array.
SetArrayAccess<
InternalSharedArrayUnionFieldsDeep<Union, Options>,
IsArrayReadonly<Union>
>;
/**
Internal helper for `SharedArrayUnionFieldsDeep`. Needn't care the `readonly` modifier of arrays.
*/
type InternalSharedArrayUnionFieldsDeep<
Union extends UnknownArray,
Options extends SharedUnionFieldsDeepOptions,
ResultTuple extends UnknownArray = [],
> =
// We should build a minimum possible length tuple where each element in the tuple exists in the union tuple.
IsNever<TupleLength<Union>> extends true
// Rule 1: If all the arrays in the union have non-fixed lengths,
// like `Array<string> | [number, ...string[]]`
// we should build a tuple that is [the_fixed_parts_of_union, ...the_rest_of_union[]].
// For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, ...string[]]>`
// => `[string | number, ...string[]]`.
? ResultTuple['length'] extends UnionMax<StaticPartOfArray<Union>['length']>
? [
// The fixed-length part of the tuple.
...ResultTuple,
// The rest of the union.
// Due to `ResultTuple` is the maximum possible fixed-length part of the tuple,
// so we can use `StaticPartOfArray` to get the rest of the union.
...Array<
SharedUnionFieldsDeep<VariablePartOfArray<Union>[number], Options>
>,
]
// Build the fixed-length tuple recursively.
: InternalSharedArrayUnionFieldsDeep<
Union, Options,
[...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
>
// Rule 2: If at least one of the arrays in the union have fixed lengths,
// like `Array<string> | [number, string]`,
// we should build a tuple of the smallest possible length to ensure any
// item in the result tuple exists in the union tuple.
// For example: `InternalSharedArrayUnionFieldsDeep<Array<string> | [number, string]>`
// => `[string | number, string]`.
: ResultTuple['length'] extends UnionMin<TupleLength<Union>>
? ResultTuple
// As above, build tuple recursively.
: InternalSharedArrayUnionFieldsDeep<
Union, Options,
[...ResultTuple, SharedUnionFieldsDeep<Union[ResultTuple['length']], Options>]
>;
/**
Omit properties from a deeply-nested object.
It supports recursing into arrays.
It supports removing specific items from an array, replacing each removed item with unknown at the specified index.
Use-case: Remove unneeded parts of complex objects.
Use [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) if you only need one level deep.
@example
```
import type {OmitDeep} from 'type-fest';
type Info = {
userInfo: {
name: string;
uselessInfo: {
foo: string;
};
};
};
type UsefulInfo = OmitDeep<Info, 'userInfo.uselessInfo'>;
// type UsefulInfo = {
// userInfo: {
// name: string;
// };
// };
// Supports removing multiple paths
type Info1 = {
userInfo: {
name: string;
uselessField: string;
uselessInfo: {
foo: string;
};
};
};
type UsefulInfo1 = OmitDeep<Info1, 'userInfo.uselessInfo' | 'userInfo.uselessField'>;
// type UsefulInfo1 = {
// userInfo: {
// name: string;
// };
// };
// Supports array
type A = OmitDeep<[1, 'foo', 2], 1>;
// type A = [1, unknown, 2];
// Supports recursing into array
type Info1 = {
address: [
{
street: string
},
{
street2: string,
foo: string
};
];
}
type AddressInfo = OmitDeep<Info1, 'address.1.foo'>;
// type AddressInfo = {
// address: [
// {
// street: string;
// },
// {
// street2: string;
// };
// ];
// };
```
@category Object
@category Array
*/
type OmitDeep<T, PathUnion extends LiteralUnion<Paths<T>, string>> =
SimplifyDeep<
SharedUnionFieldsDeep<
{[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion]
>,
UnknownArray>;
/**
Omit one path from the given object/array.
*/
type OmitDeepWithOnePath<T, Path extends string | number> =
T extends NonRecursiveType
? T
: T extends UnknownArray ? SetArrayAccess<OmitDeepArrayWithOnePath<T, Path>, IsArrayReadonly<T>>
: T extends object ? OmitDeepObjectWithOnePath<T, Path>
: T;
/**
Omit one path from the given object.
*/
type OmitDeepObjectWithOnePath<ObjectT extends