atomaric
Version:
Manage your project state
164 lines (148 loc) • 7.59 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
export type Path<T, Sep extends string> = T extends any ? PathInternal<T, Sep> : never;
export type PathValue<T, Sep extends string, ValuePath extends Path<T, Sep>> = TPathValue<T, Sep, ValuePath>;
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
type PathInternal<T, Sep extends string, TraversedTypes = T> = T extends ReadonlyArray<infer V>
? IsTuple<T> extends true
? {
[K in TupleKeys<T>]-?: PathImpl<K & string, Sep, T[K], TraversedTypes>;
}[TupleKeys<T>]
: PathImpl<ArrayKey, Sep, V, TraversedTypes>
: {
[K in keyof T]-?: PathImpl<K & (string | number), Sep, T[K], TraversedTypes>;
}[keyof T];
type TupleKeys<T extends ReadonlyArray<any>> = Exclude<keyof T, keyof any[]>;
type PathImpl<K extends string | number, Sep extends string, V, TraversedTypes> = V extends
| Primitive
| BrowserNativeObject
? `${K}`
: true extends AnyIsEqual<TraversedTypes, V>
? `${K}`
: `${K}` | `${K}${Sep}${PathInternal<V, Sep, TraversedTypes | V>}`;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
type TPathValue<T, Sep extends string, P extends Path<T, Sep> | ArrayPath<T, Sep>> = T extends any
? P extends `${infer K}${Sep}${infer R}`
? K extends keyof T
? R extends Path<T[K], Sep>
? TPathValue<T[K], Sep, R>
: never
: T extends ReadonlyArray<infer V> | Partial<Record<number, infer V>> | Record<number, infer V>
? TPathValue<V, Sep, R & Path<V, Sep>>
: never
: P extends keyof T
? T[P]
: T extends ReadonlyArray<infer V> | Partial<Record<number, infer V>> | Record<number, infer V>
? V
: never
: never;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
export type PathValueDonor<
Value,
Sep extends string,
FullPath extends Path<Value, Sep> | ArrayPath<Value, Sep>,
> = Value extends any
? FullPath extends `${infer Key}${Sep}${infer KeyRest}`
? Key extends keyof Value
? KeyRest extends Path<Value[Key], Sep>
? Required<Record<Key, PathValueDonor<Value[Key], Sep, KeyRest>>>
: never
: Value extends ReadonlyArray<infer V>
? [PathValueDonor<V, Sep, KeyRest & Path<V, Sep>>]
: Value extends Partial<Record<infer K, infer V>> | Record<infer K, infer V>
? Record<K, PathValueDonor<V, Sep, KeyRest & Path<V, Sep>>>
: never
: FullPath extends keyof Value
? FullPath extends `${string}${Sep}${string}${string}`
? Required<Record<FullPath, Value[FullPath]>>
: Value extends ReadonlyArray<any>
? []
: Record<string, never>
: Value extends ReadonlyArray<infer V>
? FullPath extends `${string}${Sep}${string}${string}`
? [V]
: []
: Value extends Partial<Record<infer K, infer V>> | Record<infer K, infer V>
? Record<K, V>
: never
: never;
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
type ArrayKey = number;
type Primitive = null | undefined | string | number | boolean | symbol | bigint;
type IsTuple<T extends ReadonlyArray<any>> = number extends T['length'] ? false : true;
type BrowserNativeObject = Date | FileList | File;
type AnyIsEqual<T1, T2> = T1 extends T2 ? (IsEqual<T1, T2> extends true ? true : never) : never;
type IsEqual<T1, T2> = T1 extends T2
? (<G>() => G extends T1 ? 1 : 2) extends <G>() => G extends T2 ? 1 : 2
? true
: false
: false;
type ArrayPath<T, Sep extends string> = T extends any ? ArrayPathInternal<T, Sep> : never;
type ArrayPathInternal<T, Sep extends string, TraversedTypes = T> = T extends ReadonlyArray<infer V>
? IsTuple<T> extends true
? {
[K in TupleKeys<T>]-?: ArrayPathImpl<K & string, Sep, T[K], TraversedTypes>;
}[TupleKeys<T>]
: ArrayPathImpl<ArrayKey, Sep, V, TraversedTypes>
: {
[K in keyof T]-?: ArrayPathImpl<K & string, Sep, T[K], TraversedTypes>;
}[keyof T];
type ArrayPathImpl<K extends string | number, Sep extends string, V, TraversedTypes> = V extends
| Primitive
| BrowserNativeObject
? IsAny<V> extends true
? string
: never
: V extends ReadonlyArray<infer U>
? U extends Primitive | BrowserNativeObject
? IsAny<V> extends true
? string
: never
: true extends AnyIsEqual<TraversedTypes, V>
? never
: `${K}` | `${K}${Sep}${ArrayPathInternal<V, Sep, TraversedTypes | V>}`
: true extends AnyIsEqual<TraversedTypes, V>
? never
: `${K}${Sep}${ArrayPathInternal<V, Sep, TraversedTypes | V>}`;
type IsAny<T> = 0 extends 1 & T ? true : false;