type-fest
Advanced tools
| import type {ToString} from './internal'; | ||
| import type {EmptyObject} from './empty-object'; | ||
| import type {IsAny} from './is-any'; | ||
| import type {IsNever} from './is-never'; | ||
| import type {UnknownArray} from './unknown-array'; | ||
| import type {UnknownRecord} from './unknown-record'; | ||
| /** | ||
| Return the part of the given array with a fixed index. | ||
| @example | ||
| ``` | ||
| type A = [string, number, boolean, ...string[]]; | ||
| type B = FilterFixedIndexArray<A>; | ||
| //=> [string, number, boolean] | ||
| ``` | ||
| */ | ||
| type FilterFixedIndexArray<T extends UnknownArray, Result extends UnknownArray = []> = | ||
| number extends T['length'] ? | ||
| T extends readonly [infer U, ...infer V] | ||
| ? FilterFixedIndexArray<V, [...Result, U]> | ||
| : Result | ||
| : T; | ||
| /** | ||
| Return the part of the given array with a non-fixed index. | ||
| @example | ||
| ``` | ||
| type A = [string, number, boolean, ...string[]]; | ||
| type B = FilterNotFixedIndexArray<A>; | ||
| //=> string[] | ||
| ``` | ||
| */ | ||
| type FilterNotFixedIndexArray<T extends UnknownArray> = | ||
| T extends readonly [...FilterFixedIndexArray<T>, ...infer U] | ||
| ? U | ||
| : []; | ||
| /** | ||
| 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 | ||
| */ | ||
| export type Paths<T extends UnknownRecord | UnknownArray> = | ||
| 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<FilterFixedIndexArray<T>> | ||
| | InternalPaths<Array<FilterNotFixedIndexArray<T>[number]>> | ||
| : InternalPaths<T> | ||
| : InternalPaths<T>; | ||
| export type InternalPaths<_T extends UnknownRecord | UnknownArray, T = Required<_T>> = | ||
| T extends EmptyObject | readonly [] | ||
| ? never | ||
| : { | ||
| [Key in keyof T]: | ||
| Key extends string | number // Limit `Key` to string or number. | ||
| ? T[Key] extends UnknownRecord | UnknownArray | ||
| ? ( | ||
| IsNever<Paths<T[Key]>> extends false | ||
| // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work. | ||
| ? Key | ToString<Key> | `${Key}.${Paths<T[Key]>}` | ||
| : Key | ToString<Key> | ||
| ) | ||
| : Key | ToString<Key> | ||
| : never | ||
| }[keyof T & (T extends UnknownArray ? number : unknown)]; |
| import type {BuildObject, BuildTuple, ToString} from './internal'; | ||
| import type {Paths} from './paths'; | ||
| import type {Simplify} from './simplify.d'; | ||
| import type {UnionToIntersection} from './union-to-intersection.d'; | ||
| import type {UnknownArray} from './unknown-array'; | ||
| import type {UnknownRecord} from './unknown-record.d'; | ||
| /** | ||
| Pick properties from a deeply-nested object. | ||
| It supports recursing into arrays. | ||
| Use-case: Distill complex objects down to the components you need to target. | ||
| @example | ||
| ``` | ||
| import type {PickDeep, PartialDeep} from 'type-fest'; | ||
| type Configuration = { | ||
| userConfig: { | ||
| name: string; | ||
| age: number; | ||
| address: [ | ||
| { | ||
| city1: string; | ||
| street1: string; | ||
| }, | ||
| { | ||
| city2: string; | ||
| street2: string; | ||
| } | ||
| ] | ||
| }; | ||
| otherConfig: any; | ||
| }; | ||
| type NameConfig = PickDeep<Configuration, 'userConfig.name'>; | ||
| // type NameConfig = { | ||
| // userConfig: { | ||
| // name: string; | ||
| // }; | ||
| // Supports optional properties | ||
| type User = PickDeep<PartialDeep<Configuration>, 'userConfig.name' | 'userConfig.age'>; | ||
| // type User = { | ||
| // userConfig?: { | ||
| // name?: string; | ||
| // age?: number; | ||
| // }; | ||
| // }; | ||
| // Supports array | ||
| type AddressConfig = PickDeep<Configuration, `userConfig.address.0`>; | ||
| // type AddressConfig = { | ||
| // userConfig: { | ||
| // address: [{ | ||
| // city1: string; | ||
| // street1: string; | ||
| // }]; | ||
| // }; | ||
| // } | ||
| // Supports recurse into array | ||
| type Street = PickDeep<Configuration, `userConfig.address.1.street2`>; | ||
| // type AddressConfig = { | ||
| // userConfig: { | ||
| // address: [ | ||
| // unknown, | ||
| // {street2: string} | ||
| // ]; | ||
| // }; | ||
| // } | ||
| ``` | ||
| @category Object | ||
| @category Array | ||
| */ | ||
| export type PickDeep<T extends UnknownRecord | UnknownArray, PathUnion extends Paths<T>> = | ||
| T extends UnknownRecord | ||
| ? Simplify<UnionToIntersection<{ | ||
| [P in PathUnion]: InternalPickDeep<T, P>; | ||
| }[PathUnion]>> | ||
| : T extends UnknownArray | ||
| ? UnionToIntersection<{ | ||
| [P in PathUnion]: InternalPickDeep<T, P>; | ||
| }[PathUnion] | ||
| > | ||
| : never; | ||
| /** | ||
| Pick an object/array from the given object/array by one path. | ||
| */ | ||
| type InternalPickDeep< | ||
| T extends UnknownRecord | UnknownArray, | ||
| Path extends string | number, // Checked paths, extracted from unchecked paths | ||
| > = | ||
| T extends UnknownArray ? PickDeepArray<T, Path> | ||
| : T extends UnknownRecord ? Simplify<PickDeepObject<T, Path>> | ||
| : never; | ||
| /** | ||
| Pick an object from the given object by one path. | ||
| */ | ||
| type PickDeepObject<RecordType extends UnknownRecord, P extends string | number> = | ||
| P extends `${infer RecordKeyInPath}.${infer SubPath}` | ||
| ? BuildObject<RecordKeyInPath, InternalPickDeep<NonNullable<RecordType[RecordKeyInPath]>, SubPath>, RecordType> | ||
| : P extends keyof RecordType | ToString<keyof RecordType> // Handle number keys | ||
| ? BuildObject<P, RecordType[P], RecordType> | ||
| : never; | ||
| /** | ||
| Pick an array from the given array by one path. | ||
| */ | ||
| type PickDeepArray<ArrayType extends UnknownArray, P extends string | number> = | ||
| // Handle paths that are `${number}.${string}` | ||
| P extends `${infer ArrayIndex extends number}.${infer SubPath}` | ||
| // When `ArrayIndex` is equal to `number` | ||
| ? number extends ArrayIndex | ||
| ? ArrayType extends unknown[] | ||
| ? Array<InternalPickDeep<NonNullable<ArrayType[number]>, SubPath>> | ||
| : ArrayType extends readonly unknown[] | ||
| ? ReadonlyArray<InternalPickDeep<NonNullable<ArrayType[number]>, SubPath>> | ||
| : never | ||
| // When `ArrayIndex` is a number literal | ||
| : ArrayType extends unknown[] | ||
| ? [...BuildTuple<ArrayIndex>, InternalPickDeep<NonNullable<ArrayType[ArrayIndex]>, SubPath>] | ||
| : ArrayType extends readonly unknown[] | ||
| ? readonly [...BuildTuple<ArrayIndex>, InternalPickDeep<NonNullable<ArrayType[ArrayIndex]>, SubPath>] | ||
| : never | ||
| // When the path is equal to `number` | ||
| : P extends `${infer ArrayIndex extends number}` | ||
| // When `ArrayIndex` is `number` | ||
| ? number extends ArrayIndex | ||
| ? ArrayType | ||
| // When `ArrayIndex` is a number literal | ||
| : ArrayType extends unknown[] | ||
| ? [...BuildTuple<ArrayIndex>, ArrayType[ArrayIndex]] | ||
| : ArrayType extends readonly unknown[] | ||
| ? readonly [...BuildTuple<ArrayIndex>, ArrayType[ArrayIndex]] | ||
| : never | ||
| : never; |
| import type {Except} from './except'; | ||
| import type {Simplify} from './simplify'; | ||
| /** | ||
| Create a type that changes the type of the given keys. | ||
| Use-cases: | ||
| - Creating variations of a base model. | ||
| - Fixing incorrect external types. | ||
| @see `Merge` if you need to change multiple properties to different types. | ||
| @example | ||
| ``` | ||
| import type {SetFieldType} from 'type-fest'; | ||
| type MyModel = { | ||
| id: number; | ||
| createdAt: Date; | ||
| updatedAt: Date; | ||
| }; | ||
| type MyModelApi = SetFieldType<MyModel, 'createdAt' | 'updatedAt', string>; | ||
| // { | ||
| // id: number; | ||
| // createdAt: string; | ||
| // updatedAt: string; | ||
| // } | ||
| ``` | ||
| @category Object | ||
| */ | ||
| export type SetFieldType<BaseType, Keys extends keyof BaseType, NewType> = | ||
| Simplify< | ||
| Except<BaseType, Keys> & | ||
| Record<Keys, NewType> | ||
| >; |
| /** | ||
| 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 | ||
| */ | ||
| export type UnknownArray = readonly unknown[]; |
+4
-0
@@ -12,2 +12,3 @@ // Basic | ||
| export type {UnknownRecord} from './source/unknown-record'; | ||
| export type {UnknownArray} from './source/unknown-array'; | ||
| export type {Except} from './source/except'; | ||
@@ -28,2 +29,3 @@ export type {TaggedUnion} from './source/tagged-union'; | ||
| export type {RequiredDeep} from './source/required-deep'; | ||
| export type {PickDeep} from './source/pick-deep'; | ||
| export type {PartialOnUndefinedDeep, PartialOnUndefinedDeepOptions} from './source/partial-on-undefined-deep'; | ||
@@ -106,2 +108,4 @@ export type {UndefinedOnPartialDeep} from './source/undefined-on-partial-deep'; | ||
| export type {ArrayValues} from './source/array-values'; | ||
| export type {SetFieldType} from './source/set-field-type'; | ||
| export type {Paths} from './source/paths'; | ||
@@ -108,0 +112,0 @@ // Template literal types |
+2
-1
| { | ||
| "name": "type-fest", | ||
| "version": "4.6.0", | ||
| "version": "4.7.0", | ||
| "description": "A collection of essential TypeScript types", | ||
@@ -14,2 +14,3 @@ "license": "(MIT OR CC0-1.0)", | ||
| "types": "./index.d.ts", | ||
| "sideEffects": false, | ||
| "engines": { | ||
@@ -16,0 +17,0 @@ "node": ">=16" |
+5
-1
@@ -116,4 +116,5 @@ <div align="center"> | ||
| - [`UnknownRecord`](source/unknown-record.d.ts) - Represents an object with `unknown` value. You probably want this instead of `{}`. | ||
| - [`UnknownArray`](source/unknown-array.d.ts) - Represents an array with `unknown` value. | ||
| - [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys). | ||
| - [`Writable`](source/writable.d.ts) - Create a type that strips `readonly` from all or some of an object's keys. The inverse of `Readonly<T>`. | ||
| - [`Writable`](source/writable.d.ts) - Create a type that strips `readonly` from the given type. Inverse of `Readonly<T>`. | ||
| - [`WritableDeep`](source/writable-deep.d.ts) - Create a deeply mutable version of an `object`/`ReadonlyMap`/`ReadonlySet`/`ReadonlyArray` type. The inverse of `ReadonlyDeep<T>`. Use `Writable<T>` if you only need one level deep. | ||
@@ -129,2 +130,3 @@ - [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type. | ||
| - [`RequiredDeep`](source/required-deep.d.ts) - Create a deeply required version of another type. Use [`Required<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) if you only need one level deep. | ||
| - [`PickDeep`](source/pick-deep.d.ts) - Pick properties from a deeply-nested object. Use [`Pick<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys) if you only need one level deep. | ||
| - [`OmitIndexSignature`](source/omit-index-signature.d.ts) - Omit any index signatures from the given object type, leaving only explicitly defined properties. | ||
@@ -180,2 +182,4 @@ - [`PickIndexSignature`](source/pick-index-signature.d.ts) - Pick only index signatures from the given object type, leaving out all explicitly defined properties. | ||
| - [`ArrayValues`](source/array-values.d.ts) - Provides all values for a constant array or tuple. | ||
| - [`SetFieldType`](source/set-field-type.d.ts) - Create a type that changes the type of the given keys. | ||
| - [`Paths`](source/paths.d.ts) - Generate a union of all possible paths to properties in the given object. | ||
@@ -182,0 +186,0 @@ ### Type Guard |
| import type {IsEqual} from './is-equal'; | ||
| import type {ConditionalExcept} from './conditional-except'; | ||
| import type {ConditionalSimplifyDeep} from './conditional-simplify'; | ||
| import type {UnknownRecord} from './unknown-record'; | ||
| import type {EmptyObject} from './empty-object'; | ||
@@ -98,5 +100,5 @@ /** | ||
| ? Type[Key] | ||
| : Type[Key] extends object | ||
| : Type[Key] extends UnknownRecord | ||
| ? ConditionalPickDeep<Type[Key], Condition, Options> | ||
| : typeof conditionalPickDeepSymbol; | ||
| }, (typeof conditionalPickDeepSymbol | undefined) | Record<PropertyKey, never>>>; | ||
| }, (typeof conditionalPickDeepSymbol | undefined) | EmptyObject>, never, UnknownRecord>; |
+32
-0
@@ -5,2 +5,3 @@ import type {Primitive} from './primitive'; | ||
| import type {IsAny} from './is-any'; | ||
| import type {UnknownRecord} from './unknown-record'; | ||
@@ -29,2 +30,33 @@ // TODO: Remove for v5. | ||
| /** | ||
| Create an object type with the given key `<Key>` and value `<Value>`. | ||
| It will copy the prefix and optional status of the same key from the given object `CopiedFrom` into the result. | ||
| @example | ||
| ``` | ||
| type A = BuildObject<'a', string>; | ||
| //=> {a: string} | ||
| // Copy `readonly` and `?` from the key `a` of `{readonly a?: any}` | ||
| type B = BuildObject<'a', string, {readonly a?: any}>; | ||
| //=> {readonly a?: string} | ||
| ``` | ||
| */ | ||
| export type BuildObject<Key extends PropertyKey, Value, CopiedFrom extends UnknownRecord = {}> = | ||
| Key extends keyof CopiedFrom | ||
| ? Pick<{[_ in keyof CopiedFrom]: Value}, Key> | ||
| : Key extends `${infer NumberKey extends number}` | ||
| ? NumberKey extends keyof CopiedFrom | ||
| ? Pick<{[_ in keyof CopiedFrom]: Value}, NumberKey> | ||
| : {[_ in Key]: Value} | ||
| : {[_ in Key]: Value}; | ||
| /** | ||
| Return a string representation of the given string or number. | ||
| Note: This type is not the return type of the `.toString()` function. | ||
| */ | ||
| export type ToString<T> = T extends string | number ? `${T}` : never; | ||
| /** | ||
| Create a tuple of length `A` and a tuple composed of two other tuples, | ||
@@ -31,0 +63,0 @@ the inferred tuple `U` and a tuple of length `B`, then extracts the length of tuple `U`. |
@@ -1,2 +0,2 @@ | ||
| import type {BuiltIns} from './internal'; | ||
| import type {BuiltIns, UnknownRecord} from './internal'; | ||
@@ -72,4 +72,5 @@ /** | ||
| ? PartialReadonlySetDeep<ItemType, Options> | ||
| : T extends object | ||
| ? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156 | ||
| : T extends UnknownRecord | ||
| ? PartialObjectDeep<T, Options> | ||
| : T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156 | ||
| ? Options['recurseIntoArrays'] extends true | ||
@@ -82,4 +83,3 @@ ? ItemType[] extends T // Test for arrays (non-tuples) specifically | ||
| : T // If they don't opt into array testing, just use the original type | ||
| : PartialObjectDeep<T, Options> | ||
| : unknown; | ||
| : T; | ||
@@ -86,0 +86,0 @@ /** |
+35
-7
@@ -5,4 +5,18 @@ import type {Except} from './except'; | ||
| /** | ||
| Create a type that strips `readonly` from all or some of an object's keys. Inverse of `Readonly<T>`. | ||
| Create a writable version of the given array type. | ||
| */ | ||
| type WritableArray<ArrayType extends readonly unknown[]> = | ||
| ArrayType extends readonly [] ? [] | ||
| : ArrayType extends readonly [...infer U, infer V] ? [...U, V] | ||
| : ArrayType extends readonly [infer U, ...infer V] ? [U, ...V] | ||
| : ArrayType extends ReadonlyArray<infer U> ? U[] | ||
| : ArrayType; | ||
| /** | ||
| Create a type that strips `readonly` from the given type. Inverse of `Readonly<T>`. | ||
| The 2nd argument will be ignored if the input type is not an object. | ||
| Note: This type can make readonly `Set` and `Map` writable. This behavior is different from `Readonly<T>` (as of TypeScript 5.2.2). See: https://github.com/microsoft/TypeScript/issues/29655 | ||
| This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509), or to define a single model where the only thing that changes is whether or not some of the keys are writable. | ||
@@ -31,2 +45,8 @@ | ||
| // } | ||
| // Also supports array | ||
| const readonlyArray: readonly number[] = [1, 2, 3]; | ||
| readonlyArray.push(4); // Will fail as the array itself is readonly. | ||
| const writableArray: Writable<typeof readonlyArray> = readonlyArray as Writable<typeof readonlyArray>; | ||
| writableArray.push(4); // Will work as the array itself is now writable. | ||
| ``` | ||
@@ -37,7 +57,15 @@ | ||
| export type Writable<BaseType, Keys extends keyof BaseType = keyof BaseType> = | ||
| Simplify< | ||
| // Pick just the keys that are not writable from the base type. | ||
| Except<BaseType, Keys> & | ||
| // Pick the keys that should be writable from the base type and make them writable by removing the `readonly` modifier from the key. | ||
| {-readonly [KeyType in keyof Pick<BaseType, Keys>]: Pick<BaseType, Keys>[KeyType]} | ||
| >; | ||
| BaseType extends ReadonlyMap<infer KeyType, infer ValueType> | ||
| ? Map<KeyType, ValueType> | ||
| : BaseType extends ReadonlySet<infer ItemType> | ||
| ? Set<ItemType> | ||
| : BaseType extends readonly unknown[] | ||
| // Handle array | ||
| ? WritableArray<BaseType> | ||
| // Handle object | ||
| : Simplify< | ||
| // Pick just the keys that are not writable from the base type. | ||
| Except<BaseType, Keys> & | ||
| // Pick the keys that should be writable from the base type and make them writable by removing the `readonly` modifier from the key. | ||
| {-readonly [KeyType in keyof Pick<BaseType, Keys>]: Pick<BaseType, Keys>[KeyType]} | ||
| >; |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
307774
3.84%120
3.45%7186
4.72%956
0.42%16
6.67%