Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

type-fest

Package Overview
Dependencies
Maintainers
1
Versions
190
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

type-fest - npm Package Compare versions

Comparing version
4.6.0
to
4.7.0
+107
source/paths.d.ts
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"

@@ -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>;

@@ -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 @@ /**

@@ -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]}
>;