import { StaticPartOfArray, UnknownArray, VariablePartOfArray } from "./array.cjs"; import { BuildTuple, EmptyObject, Index40, IsAny, IsNever, IsPrimitive, NonRecursiveType, Nullable, Nullish, Primitive, Simplify } from "./base.cjs"; import { StringKeyOf } from "./json.cjs"; import { Numeric } from "./number.cjs"; import { StringDigit } from "./string.cjs"; import { IsNotFalse, LessThan, Sum } from "./logic.cjs"; //#region src/object.d.ts /** * Returns a boolean for whether the given type is an empty object. */ type IsEmptyObject = T extends EmptyObject ? true : false; /** * Returns a boolean for whether the given type is a plain key-value object. */ type IsPlainObject = T extends NonRecursiveType | ReadonlyMap | ReadonlySet | UnknownArray ? false : T extends object ? true : false; type LiteralCheck = IsNever extends false ? [T] extends [LiteralType & infer U] ? [U] extends [LiteralType] ? [LiteralType] extends [U] ? false : true : false : false : false; type LiteralChecks = IsNotFalse : never>; /** * Returns a boolean for whether the given type is a string literal. */ type IsStringLiteral = LiteralCheck; /** * Returns a boolean for whether the given type is a numeric literal. */ type IsNumericLiteral = LiteralChecks; /** * Returns a boolean for whether the given type is a boolean literal. */ type IsBooleanLiteral = LiteralCheck; /** * Returns a boolean for whether the given type is a symbol literal. */ type IsSymbolLiteral = LiteralCheck; type IsLiteralUnion = IsBooleanLiteral | IsNumericLiteral | IsStringLiteral | IsSymbolLiteral; /** * Returns a boolean for whether the given type is a literal type. */ type IsLiteral = IsPrimitive extends true ? IsNotFalse> : false; /** * Returns a boolean for whether the given type is an object. */ type LiteralKeyOf = keyof { [K in keyof T as IsLiteral extends true ? K : never]-?: never }; /** * 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. * ``` */ type LiteralUnion = (BaseType & Record) | LiteralType; /** * Create an object type with the given key `` and 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} * ``` */ type BuildObject = 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. */ type ToString = T extends number | string ? `${T}` : never; /** * Extract the object field type if T is an object and K is a key of T, return `never` otherwise. * * It creates a type-safe way to access the member type of `unknown` type. */ type ObjectValue = K extends keyof T ? T[K] : ToString extends keyof T ? T[ToString] : K extends `${infer NumberK extends number}` ? NumberK extends keyof T ? T[NumberK] : never : never; type Paths = InnerPaths; type InnerPaths = T extends NonRecursiveType | ReadonlyMap | ReadonlySet ? never : IsAny extends true ? never : T extends UnknownArray ? number extends T["length"] ? InternalPaths[number][], Depth> | InternalPaths, Depth> : InternalPaths : T extends object ? InternalPaths : never; type InternalPaths> = T extends EmptyObject | readonly [] ? never : { [Key in keyof T]: Key extends number | string ? Key | (LessThan extends true ? IsNever>> extends false ? `${Key}.${InnerPaths>}` : never : never) | ToString : never }[(T extends UnknownArray ? number : unknown) & keyof T]; interface GetOptions { /** * Include `undefined` in the return type when accessing properties. * * Setting this to `false` is not recommended. * * @defaultValue `true` */ strict?: boolean; } /** * Like the `Get` type but receives an array of strings as a path parameter. */ type GetWithPath = Keys extends readonly [] ? BaseType : Keys extends readonly [infer Head, ...infer Tail] ? GetWithPath, Options>, Extract, Options> : never; /** * Adds `undefined` to `Type` if `strict` is enabled. */ type Strictify = Options["strict"] extends false ? Type : Type | undefined; /** * If `Options['strict']` is `true`, includes `undefined` in the returned type when accessing properties on `Record`. * * Known limitations: * - Does not include `undefined` in the type on object types with an index signature (for example, `{a: string; [key: string]: string}`). */ type StrictPropertyOf = Record extends BaseType ? string extends keyof BaseType ? Strictify : BaseType[Key] : BaseType[Key]; /** * Represents an array of strings split using a given character or character set. * * Use-case: Defining the return type of a method like `String.prototype.split`. * * @example * ``` * import type {Split} from 'type-fest'; * * declare function split(string: S, separator: D): Split; * * type Item = 'foo' | 'bar' | 'baz' | 'waldo'; * const items = 'foo,bar,baz,waldo'; * let array: Item[]; * * array = split(items, ','); * ``` */ type Split = S extends `${infer Head}${Delimiter}${infer Tail}` ? [Head, ...Split] : S extends Delimiter ? [] : [S]; /** * Splits a dot-prop style path into a tuple comprised of the properties in the path. Handles square-bracket notation. * * @example * ``` * ToPath<'foo.bar.baz'> * //=> ['foo', 'bar', 'baz'] * * ToPath<'foo[0].bar.baz'> * //=> ['foo', '0', 'bar', 'baz'] * ``` */ type ToPath = Split, ".">; /** * Replaces square-bracketed dot notation with dots, for example, `foo[0].bar` -\> `foo.0.bar`. */ type FixPathSquareBrackets = Path extends `[${infer Head}]${infer Tail}` ? Tail extends `[${string}` ? `${Head}.${FixPathSquareBrackets}` : `${Head}${FixPathSquareBrackets}` : Path extends `${infer Head}[${infer Middle}]${infer Tail}` ? `${Head}.${FixPathSquareBrackets<`[${Middle}]${Tail}`>}` : Path; /** * Returns true if `LongString` is made up out of `Substring` repeated 0 or more times. * * @example * ```ts * ConsistsOnlyOf<'aaa', 'a'> //=> true * ConsistsOnlyOf<'ababab', 'ab'> //=> true * ConsistsOnlyOf<'aBa', 'a'> //=> false * ConsistsOnlyOf<'', 'a'> //=> true * ``` * */ type ConsistsOnlyOf = LongString extends "" ? true : LongString extends `${Substring}${infer Tail}` ? ConsistsOnlyOf : false; /** * Convert a type which may have number keys to one with string keys, making it possible to index using strings retrieved from template types. * * @example * * ```ts * type WithNumbers = {foo: string; 0: boolean}; * type WithStrings = WithStringKeys; * * type WithNumbersKeys = keyof WithNumbers; * //=> 'foo' | 0 * type WithStringsKeys = keyof WithStrings; * //=> 'foo' | '0' * ``` * */ type WithStringKeys = { [Key in StringKeyOf]: UncheckedIndex }; /** Perform a `T[U]` operation if `T` supports indexing. */ type UncheckedIndex = [T] extends [Record] ? T[U] : never; /** * Get a property of an object or array. Works when indexing arrays using number-literal-strings, for example, `PropertyOf = number`, and when indexing objects with number keys. * * Note: * - Returns `unknown` if `Key` is not a property of `BaseType`, since TypeScript uses structural typing, and it cannot be guaranteed that extra properties unknown to the type system will exist at runtime. * - Returns `undefined` from nullish values, to match the behavior of most deep-key libraries like `lodash`, `dot-prop`, etc. */ type PropertyOf = BaseType extends Nullish ? undefined : Key extends keyof BaseType ? StrictPropertyOf : BaseType extends readonly [] | readonly [unknown, ...unknown[]] ? unknown : BaseType extends { [n: number]: infer Item; length: number; } ? ConsistsOnlyOf extends true ? Strictify : unknown : Key extends keyof WithStringKeys ? StrictPropertyOf, Key, Options> : unknown; /** * Get a deeply-nested property from an object using a key path, like Lodash's `.get()` function. * * Use-case: Retrieve a property from deep inside an API response or some other complex object. * * @example * ``` * import type {Get} from 'type-fest'; * import * as lodash from 'lodash'; * * const get = (object: BaseType, path: Path): Get => * lodash.get(object, path); * * interface ApiResponse { * hits: { * hits: Array<{ * _id: string * _source: { * name: Array<{ * given: string[] * family: string * }> * birthDate: string * } * }> * } * } * * const getName = (apiResponse: ApiResponse) => * get(apiResponse, 'hits.hits[0]._source.name'); * //=> Array<{given: string[]; family: string}> | undefined * * // Path also supports a readonly array of strings * const getNameWithPathArray = (apiResponse: ApiResponse) => * get(apiResponse, ['hits','hits', '0', '_source', 'name'] as const); * //=> Array<{given: string[]; family: string}> | undefined * * // Non-strict mode: * Get //=> string * Get, 'foo', {strict: true}> // => string * ``` */ type Get> = GetWithPath : Path, Options>; /** * Convert a union type to an intersection type using [distributive conditional types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). * * Inspired by [this Stack Overflow answer](https://stackoverflow.com/a/50375286/2172153). * * @example * ``` * import type {UnionToIntersection} from 'type-fest'; * * type Union = {the(): void} | {great(arg: string): void} | {escape: boolean}; * * type Intersection = UnionToIntersection; * //=> {the(): void; great(arg: string): void; escape: boolean}; * ``` * * A more applicable example which could make its way into your library code follows. * * @example * ``` * import type {UnionToIntersection} from 'type-fest'; * * class CommandOne { * commands: { * a1: () => undefined, * b1: () => undefined, * } * } * * class CommandTwo { * commands: { * a2: (argA: string) => undefined, * b2: (argB: string) => undefined, * } * } * * const union = [new CommandOne(), new CommandTwo()].map(instance => instance.commands); * type Union = typeof union; * //=> {a1(): void; b1(): void} | {a2(argA: string): void; b2(argB: string): void} * * type Intersection = UnionToIntersection; * //=> {a1(): void; b1(): void; a2(argA: string): void; b2(argB: string): void} * ``` */ type UnionToIntersection = (Union extends unknown ? (_distributedUnion: Union) => void : never) extends ((_mergedIntersection: infer Intersection) => void) ? // The `& Union` is to allow indexing by the resulting type Intersection & Union : never; /** * 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; * // type NameConfig = { * // userConfig: { * // name: string; * // } * // }; * * // Supports optional properties * type User = PickDeep, 'userConfig.name' | 'userConfig.age'>; * // type User = { * // userConfig?: { * // name?: string; * // age?: number; * // }; * // }; * * // Supports array * type AddressConfig = PickDeep; * // type AddressConfig = { * // userConfig: { * // address: [{ * // city1: string; * // street1: string; * // }]; * // }; * // } * * // Supports recurse into array * type Street = PickDeep; * // type Street = { * // userConfig: { * // address: [ * // unknown, * // {street2: string} * // ]; * // }; * // } * ``` */ type PickDeep> = T extends NonRecursiveType ? never : T extends UnknownArray ? UnionToIntersection<{ [P in PathUnion]: InternalPickDeep }[PathUnion]> : T extends object ? Simplify }[PathUnion]>> : never; /** * Pick an object/array from the given object/array by one path. */ type InternalPickDeep = T extends NonRecursiveType ? never : T extends UnknownArray ? PickDeepArray : T extends object ? Simplify> : never; /** * Pick an object from the given object by one path. */ type PickDeepObject = P extends `${infer RecordKeyInPath}.${infer SubPath}` ? ObjectValue extends infer ObjectV ? IsNever extends false ? BuildObject, SubPath>, RecordType> : never : never : ObjectValue extends infer ObjectV ? IsNever extends false ? BuildObject : never : never; /** * Pick an array from the given array by one path. */ type PickDeepArray = P extends `${infer ArrayIndex extends number}.${infer SubPath}` ? number extends ArrayIndex ? ArrayType extends unknown[] ? InternalPickDeep, SubPath>[] : ArrayType extends readonly unknown[] ? readonly InternalPickDeep, SubPath>[] : never : ArrayType extends unknown[] ? [...BuildTuple, InternalPickDeep, SubPath>] : ArrayType extends readonly unknown[] ? readonly [...BuildTuple, InternalPickDeep, SubPath>] : never : P extends `${infer ArrayIndex extends number}` ? number extends ArrayIndex ? ArrayType : ArrayType extends unknown[] ? [...BuildTuple, ArrayType[ArrayIndex]] : ArrayType extends readonly unknown[] ? readonly [...BuildTuple, ArrayType[ArrayIndex]] : never : never; type IsTuple = T extends { length: infer Length; } & readonly any[] ? Length extends Index40 ? T : never : never; type AllowedIndexes = Tuple extends readonly [] ? Keys : Tuple extends readonly [infer _First, ...infer Tail] ? AllowedIndexes : Keys; type PrefixArrayAccessor = { [K in keyof T]: `[${number}]${DeepKey}` }[number]; type PrefixTupleAccessor = { [K in TIndex]: `[${K}]${DeepKey}` | `[${K}]` }[TIndex]; type PrefixObjectAccessor = { [K in keyof T]-?: K extends number | string ? `${PrefixFromDepth}${DeepKey}` | PrefixFromDepth : never }[keyof T]; type PrefixFromDepth = TDepth["length"] extends 0 ? T : `.${T}`; type DeepKey = TDepth["length"] extends 5 ? never : unknown extends T ? PrefixFromDepth : T extends IsTuple & any[] ? PrefixTupleAccessor, TDepth> : T extends any[] ? PrefixArrayAccessor : T extends Date ? never : T extends object ? PrefixObjectAccessor : T extends bigint | boolean | number | string ? "" : never; type DeepValue, TPath extends DeepKey> = GetWithPath>; type NullableDeepValue, TPath extends DeepKey> = Nullable>>; /** * Recursively traverse an object type and replace all property types with `TProperty`. */ type ReplaceObjectProperties = TObject extends object ? { [K in keyof TObject]: ReplaceObjectProperties } : TProperty; //#endregion export { BuildObject, DeepKey, DeepValue, Get, GetWithPath, InternalPaths, IsBooleanLiteral, IsEmptyObject, IsLiteral, IsNumericLiteral, IsPlainObject, IsStringLiteral, IsSymbolLiteral, LiteralKeyOf, LiteralUnion, NullableDeepValue, ObjectValue, Paths, PickDeep, PropertyOf, ReplaceObjectProperties, Split, ToPath, ToString, UnionToIntersection }; //# sourceMappingURL=object.d.cts.map