-
-
Notifications
You must be signed in to change notification settings - Fork 533
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Sindre Sorhus <[email protected]>
- Loading branch information
1 parent
3ec8dba
commit 0e196aa
Showing
8 changed files
with
493 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import type {BuildTuple, Subtract, StaticPartOfArray, VariablePartOfArray, GTE} from './internal'; | ||
import type {UnknownArray} from './unknown-array'; | ||
|
||
/** | ||
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] | ||
: GTE<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 | ||
*/ | ||
export 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import type {ArraySplice} from './array-splice'; | ||
import type {ExactKey, IsArrayReadonly, NonRecursiveType, SetArrayAccess, ToString} from './internal'; | ||
import type {IsEqual} from './is-equal'; | ||
import type {SimplifyDeep} from './merge-deep'; | ||
import type {Paths} from './paths'; | ||
import type {SharedUnionFieldsDeep} from './shared-union-fields-deep'; | ||
import type {UnknownArray} from './unknown-array'; | ||
|
||
/** | ||
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 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 | ||
*/ | ||
export type OmitDeep<T, PathUnion extends Paths<T>> = | ||
SimplifyDeep< | ||
SharedUnionFieldsDeep< | ||
{[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion] | ||
> | ||
>; | ||
|
||
/** | ||
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 object, P extends string | number> = | ||
P extends `${infer RecordKeyInPath}.${infer SubPath}` | ||
? { | ||
[Key in keyof ObjectT]: | ||
IsEqual<RecordKeyInPath, ToString<Key>> extends true | ||
? ExactKey<ObjectT, Key> extends infer RealKey | ||
? RealKey extends keyof ObjectT | ||
? OmitDeepWithOnePath<ObjectT[RealKey], SubPath> | ||
: ObjectT[Key] | ||
: ObjectT[Key] | ||
: ObjectT[Key] | ||
} | ||
: ExactKey<ObjectT, P> extends infer Key | ||
? Key extends PropertyKey | ||
? Omit<ObjectT, Key> | ||
: ObjectT | ||
: ObjectT; | ||
|
||
/** | ||
Omit one path from from the given array. | ||
It replaces the item to `unknown` at the given index. | ||
@example | ||
``` | ||
type A = OmitDeepArrayWithOnePath<[10, 20, 30, 40], 2>; | ||
//=> type A = [10, 20, unknown, 40]; | ||
``` | ||
*/ | ||
type OmitDeepArrayWithOnePath<ArrayType extends UnknownArray, P extends string | number> = | ||
// Handle paths that are `${number}.${string}` | ||
P extends `${infer ArrayIndex extends number}.${infer SubPath}` | ||
// If `ArrayIndex` is equal to `number` | ||
? number extends ArrayIndex | ||
? Array<OmitDeepWithOnePath<NonNullable<ArrayType[number]>, SubPath>> | ||
// If `ArrayIndex` is a number literal | ||
: ArraySplice<ArrayType, ArrayIndex, 1, [OmitDeepWithOnePath<NonNullable<ArrayType[ArrayIndex]>, SubPath>]> | ||
// If the path is equal to `number` | ||
: P extends `${infer ArrayIndex extends number}` | ||
// If `ArrayIndex` is `number` | ||
? number extends ArrayIndex | ||
? [] | ||
// If `ArrayIndex` is a number literal | ||
: ArraySplice<ArrayType, ArrayIndex, 1, [unknown]> | ||
: never; |
Oops, something went wrong.