import type {BuildObject, BuildTuple, NonRecursiveType, ObjectValue} from './internal'; import type {IsNever} from './is-never'; 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'; /** 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} // ]; // }; // } ``` @category Object @category Array */ export 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 = // 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, SubPath>> : ArrayType extends readonly unknown[] ? ReadonlyArray, SubPath>> : never // When `ArrayIndex` is a number literal : ArrayType extends unknown[] ? [...BuildTuple, InternalPickDeep, SubPath>] : ArrayType extends readonly unknown[] ? readonly [...BuildTuple, InternalPickDeep, 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, ArrayType[ArrayIndex]] : ArrayType extends readonly unknown[] ? readonly [...BuildTuple, ArrayType[ArrayIndex]] : never : never;