11import type { IfArray , IfArrayLike } from './arrays.js' ;
22import type { Primitive } from './common.js' ;
3- import type { CamelCase } from './strings.js' ;
3+ import type { UnknownRecord } from './records.js' ;
4+ import type { AutoCompletableString , CamelCase } from './strings.js' ;
45import type { KeyValueTuple } from './tuples.js' ;
5- import type { CanBeUndefined , IfNever } from './utils.js' ;
6+ import type { CanBeUndefined , IfNever , Pretty } from './utils.js' ;
67
78export type Assign < Target , Source > = IfNever < Target , Source , Omit < Target , keyof ( Target | Source ) > & Source > ;
89
@@ -119,7 +120,7 @@ export type GetValueForKey<
119120 */
120121export type PathValue <
121122 Type extends object ,
122- TargetPath extends Path < Type > ,
123+ TargetPath extends Path < Type > | AutoCompletableString | number ,
123124 Optional extends boolean = CanBeUndefined < Type , true , false > ,
124125> = TargetPath extends `${infer Key } .${infer Rest } `
125126 ? GetValueForKey < Type , Key , Optional > extends infer Value
@@ -132,3 +133,54 @@ export type PathValue<
132133export type PathValues < Type extends object , TargetPaths extends Path < Type > > = {
133134 [ TargetPath in TargetPaths as CamelCase < `${TargetPath } `, '.' > ] : PathValue < Type , TargetPath > ;
134135} ;
136+
137+ export type FromPath < TargetPath extends PropertyKey , Value > = TargetPath extends `${infer Key } .${infer Rest } `
138+ ? { [ K in Key ] : FromPath < Rest , Value > }
139+ : { [ K in TargetPath ] : Value } ;
140+
141+ /**
142+ * Get a union of all intermediate paths, ending with `TargetPath`
143+ */
144+ export type AllPaths < TargetPath extends PropertyKey > = TargetPath extends `${infer Head } .${infer Tail } `
145+ ? Head | `${Head } .${AllPaths < Tail > } `
146+ : TargetPath ;
147+
148+ export type WithPath < Input extends object , InputPath extends PropertyKey , Value = unknown > = Pretty <
149+ Input & Merge < Input , FromPath < InputPath , Value > >
150+ > ;
151+
152+ export type Merge < Left , Right > = Left extends unknown [ ]
153+ ? Right extends Record < number , unknown >
154+ ? MergeArrayWithObject < Left , Right >
155+ : Right
156+ : Left extends object
157+ ? Right extends object
158+ ? MergeObjects < Left , Right >
159+ : Right
160+ : Right ;
161+
162+ /**
163+ * @internal
164+ */
165+ export type MergeObjects < Left , Right > = {
166+ [ Key in keyof Left | keyof Right ] : Key extends keyof Right
167+ ? Key extends keyof Left // Key exists in both Left and Right
168+ ? Merge < Left [ Key ] , Right [ Key ] >
169+ : Right [ Key ] // Key exists only in Right
170+ : Key extends keyof Left
171+ ? Left [ Key ] // Key exists only in Left
172+ : never ;
173+ } ;
174+
175+ /**
176+ * @internal
177+ */
178+ export type MergeArrayWithObject < Left extends unknown [ ] , Right extends UnknownRecord > = Left & {
179+ [ Key in keyof Right ] : Key extends keyof Left
180+ ? Merge < Left [ Key & keyof Left ] , Right [ Key ] >
181+ : Key extends `${infer Index extends number } `
182+ ? Index extends keyof Left
183+ ? Merge < Left [ Index ] , Right [ Key ] >
184+ : Right [ Key ]
185+ : Right [ Key ] ;
186+ } ;
0 commit comments