feat(typescript-types): Fully rewrite KeyPaths<T,O,F>
Rewrite KeyPaths to eleminate 'Too deep instantiations' error of TypeScript.
This commit is contained in:
5
packages/typescript-types/src/and.ts
Normal file
5
packages/typescript-types/src/and.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export type And<A extends boolean, B extends boolean> = A extends true
|
||||
? B extends true
|
||||
? true
|
||||
: false
|
||||
: false
|
||||
9
packages/typescript-types/src/concat.ts
Normal file
9
packages/typescript-types/src/concat.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { If } from './if.js'
|
||||
import type { Or } from './or.js'
|
||||
import type { IsEmptyString } from './is-empty-string.js'
|
||||
|
||||
export type Concat<Prefix extends string, Suffix extends string, Separator extends string = ''> = If<
|
||||
Or<IsEmptyString<Prefix>, IsEmptyString<Suffix>>,
|
||||
`${Prefix}${Suffix}`,
|
||||
`${Prefix}${Separator}${Suffix}`
|
||||
>
|
||||
1
packages/typescript-types/src/extends-exactly.ts
Normal file
1
packages/typescript-types/src/extends-exactly.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type ExtendsExactly<A, B> = [A] extends [B] ? true : false
|
||||
1
packages/typescript-types/src/extends.ts
Normal file
1
packages/typescript-types/src/extends.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Extends<A, B> = A extends B ? true : false
|
||||
@@ -1,5 +1,8 @@
|
||||
export type * from './and.js'
|
||||
export type * from './assign.js'
|
||||
export type * from './built-ins.js'
|
||||
export type * from './extends-exactly.js'
|
||||
export type * from './extends.js'
|
||||
export type * from './get.js'
|
||||
export type * from './if.js'
|
||||
export type * from './is-any.js'
|
||||
@@ -14,3 +17,4 @@ export type * from './optional-keys-of.js'
|
||||
export type * from './pick-assignable.js'
|
||||
export type * from './primitive.js'
|
||||
export type * from './simplify.js'
|
||||
export type * from './xor.js'
|
||||
|
||||
@@ -1,55 +1,68 @@
|
||||
import type { If } from './if.js'
|
||||
import type { IsEmptyString } from './is-empty-string.js'
|
||||
import type { IsUndefined } from './is-undefined.js'
|
||||
import type { Simplify } from './simplify.js'
|
||||
import type { Extends } from './extends.js'
|
||||
import type { Concat } from './concat.js'
|
||||
import type { Assign } from './assign.js'
|
||||
import type { NonContainerType } from './non-container-type.js'
|
||||
|
||||
interface KeyPaths_Options {
|
||||
export interface KeyPaths_Options {
|
||||
separator?: string
|
||||
leavesOnly?: boolean
|
||||
invertFilter?: boolean
|
||||
}
|
||||
|
||||
type RequiredOptions = Required<KeyPaths_Options>
|
||||
|
||||
interface KeyPaths_DefaultOptions {
|
||||
separator: '.'
|
||||
leavesOnly: true
|
||||
invertFilter: false
|
||||
}
|
||||
|
||||
type GetPrefixedKey<
|
||||
Parent extends string,
|
||||
Key extends string,
|
||||
Separator extends string
|
||||
> = `${If<IsEmptyString<Parent>, '', `${Parent}${Separator}`>}${Key}`
|
||||
type ExtendsFilter<Obj, Key extends keyof Obj, Filter> =
|
||||
Extends<Obj[Key], Filter> extends false ? false : true
|
||||
|
||||
type PrefixIfNot<Cond, Prefix, T> = If<Cond, T, Prefix | T>
|
||||
type IncludeElement<Obj, Key extends keyof Obj, Filter> = Obj extends never
|
||||
? false
|
||||
: Obj[Key] extends never
|
||||
? false
|
||||
: unknown extends Obj[Key]
|
||||
? false
|
||||
: ExtendsFilter<Obj, Key, Filter> extends false
|
||||
? true
|
||||
: false
|
||||
|
||||
type KeyPathOf<Obj, Options extends Required<KeyPaths_Options>, Parent extends string, Filter = never> =
|
||||
Obj extends Record<PropertyKey, unknown>
|
||||
? PrefixIfNot<Options['leavesOnly'], Parent, KeyPathsOfStringKeys<Obj, Options, Filter, Parent>>
|
||||
: If<IsUndefined<Obj>, never, Parent>
|
||||
type AdaptKeyForOptionals<Obj, Key extends keyof Obj> = Key extends number | string
|
||||
? undefined extends Obj[Key]
|
||||
? Obj[Key] extends undefined
|
||||
? `${Key}`
|
||||
: `${Key}?`
|
||||
: `${Key}`
|
||||
: never
|
||||
|
||||
type NonUndefined<Obj> = Obj extends undefined ? never : Obj
|
||||
type KeysOf<Obj> = Obj extends undefined ? never : Exclude<keyof Obj, keyof any[]>
|
||||
|
||||
type KeyPathsOfStringKeys<
|
||||
Obj extends object,
|
||||
Options extends Required<KeyPaths_Options>,
|
||||
Obj,
|
||||
Key extends keyof Obj,
|
||||
Options extends RequiredOptions,
|
||||
Filter,
|
||||
Parent extends string = ''
|
||||
> = {
|
||||
[Key in keyof Obj & string]: Obj[Key] extends Filter
|
||||
? If<
|
||||
Options['invertFilter'],
|
||||
KeyPathOf<Obj[Key], Options, GetPrefixedKey<Parent, Key, Options['separator']>, Filter>,
|
||||
never
|
||||
>
|
||||
: If<
|
||||
Options['invertFilter'],
|
||||
never,
|
||||
KeyPathOf<Obj[Key], Options, GetPrefixedKey<Parent, Key, Options['separator']>, Filter>
|
||||
>
|
||||
}[keyof Obj & string]
|
||||
> = Key extends Key
|
||||
? IncludeElement<Obj, Key, Filter> extends true
|
||||
? Obj[Key] extends NonContainerType
|
||||
? Concat<Parent, AdaptKeyForOptionals<Obj, Key>, Options['separator']>
|
||||
: KeyPathsOfStringKeys<
|
||||
NonUndefined<Obj[Key]>,
|
||||
KeysOf<Obj[Key]>,
|
||||
Options,
|
||||
Filter,
|
||||
Concat<Parent, AdaptKeyForOptionals<Obj, Key>, Options['separator']>
|
||||
>
|
||||
: never
|
||||
: never
|
||||
|
||||
export type KeyPaths<
|
||||
Obj extends object,
|
||||
Obj,
|
||||
Options extends KeyPaths_Options = {},
|
||||
Filter = null | undefined
|
||||
> = Simplify<KeyPathsOfStringKeys<Obj, Assign<KeyPaths_Options, KeyPaths_DefaultOptions, Options>, Filter>>
|
||||
> = KeyPathsOfStringKeys<Obj, keyof Obj, Assign<KeyPaths_Options, KeyPaths_DefaultOptions, Options>, Filter>
|
||||
|
||||
1
packages/typescript-types/src/not.ts
Normal file
1
packages/typescript-types/src/not.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Not<A extends boolean> = A extends true ? false : true
|
||||
1
packages/typescript-types/src/or.ts
Normal file
1
packages/typescript-types/src/or.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Or<A extends boolean, B extends boolean> = A extends true ? true : B extends true ? true : false
|
||||
1
packages/typescript-types/src/xor.ts
Normal file
1
packages/typescript-types/src/xor.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Xor<A extends boolean, B extends Boolean> = [A] extends [B] ? false : true
|
||||
Reference in New Issue
Block a user