feat(typescript-types): Add KeyPaths<T, F, O>

This commit is contained in:
T. R. Bernstein
2025-07-15 15:09:26 +02:00
parent 4ec764de9e
commit 3997eaa864
3 changed files with 81 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
import type { If } from './if.js'
import type { IsEmptyString } from './is-empty-string.js'
import type { Assign } from './assign.js'
interface KeyPaths_Options {
separator?: string
leavesOnly?: boolean
}
interface KeyPaths_DefaultOptions {
separator: '.'
leavesOnly: true
}
type GetPrefixedKey<
Parent extends string,
Key extends string,
Separator extends string
> = `${If<IsEmptyString<Parent>, '', `${Parent}${Separator}`>}${Key}`
type PrefixIfNot<Cond, Prefix, T> = If<Cond, T, Prefix | T>
type KeyPathOf<
Obj,
Options extends Required<KeyPaths_Options>,
Parent extends string,
Filter = never
> = Obj extends object
? PrefixIfNot<Options['leavesOnly'], Parent, KeyPathsOfStringKeys<Obj, Options, Filter, Parent>>
: Parent
type KeyPathsOfStringKeys<
Obj extends object,
Options extends Required<KeyPaths_Options>,
Filter = never,
Parent extends string = ''
> = {
[Key in keyof Obj & string]: Obj[Key] extends Filter
? never
: KeyPathOf<Obj[Key], Options, GetPrefixedKey<Parent, Key, Options['separator']>, Filter>
}[keyof Obj & string]
export type KeyPaths<
Obj extends object,
Filter = null | undefined | never,
Options extends KeyPaths_Options = {}
> = KeyPathsOfStringKeys<Obj, Assign<KeyPaths_Options, KeyPaths_DefaultOptions, Options>, Filter>