fix(typescript-types): Handle union types when filtering

This commit is contained in:
T. R. Bernstein
2025-07-16 11:23:11 +02:00
parent 3997eaa864
commit 8d51cb778c
2 changed files with 14 additions and 10 deletions

View File

@@ -29,15 +29,17 @@ type KeyPathOf<
? PrefixIfNot<Options['leavesOnly'], Parent, KeyPathsOfStringKeys<Obj, Options, Filter, Parent>>
: Parent
type DoesNotMatchFilter<T, Filter> = T extends Filter ? false : true
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>
[Key in keyof Obj & string]: DoesNotMatchFilter<Obj[Key], Filter> extends true
? KeyPathOf<Obj[Key], Options, GetPrefixedKey<Parent, Key, Options['separator']>, Filter>
: never
}[keyof Obj & string]
export type KeyPaths<

View File

@@ -4,6 +4,7 @@ import { expect } from 'tstyche'
interface ExampleObject {
nullvalue: null
simplevalue: string
optionalKey?: string
config: {
nullvalue: null
simplevalue: string
@@ -12,19 +13,20 @@ interface ExampleObject {
expect<KeyPaths<ExampleObject>>().type.toBe<'simplevalue' | 'config.simplevalue'>()
expect<KeyPaths<ExampleObject, never>>().type.toBe<
'nullvalue' | 'simplevalue' | 'config.nullvalue' | 'config.simplevalue'
'nullvalue' | 'simplevalue' | 'optionalKey' | 'config.nullvalue' | 'config.simplevalue'
>()
expect<KeyPaths<ExampleObject, null>>().type.toBe<'simplevalue' | 'config.simplevalue'>()
expect<KeyPaths<ExampleObject, null>>().type.toBe<'simplevalue' | 'optionalKey' | 'config.simplevalue'>()
expect<KeyPaths<ExampleObject, string>>().type.toBe<'nullvalue' | 'config.nullvalue'>()
expect<KeyPaths<ExampleObject, null, { separator: '-' }>>().type.toBe<'simplevalue' | 'config-simplevalue'>()
expect<KeyPaths<ExampleObject, null, { separator: '-' }>>().type.toBe<
'simplevalue' | 'optionalKey' | 'config-simplevalue'
>()
expect<KeyPaths<ExampleObject, null, { leavesOnly: false }>>().type.toBe<
'simplevalue' | 'config' | 'config.simplevalue'
'simplevalue' | 'optionalKey' | 'config' | 'config.simplevalue'
>()
expect<KeyPaths<any, string>>().type.toBe<unknown>()
expect<KeyPaths<any, never>>().type.toBe<unknown>()
expect<KeyPaths<any, string>>().type.toBeAssignableTo<never>()
expect<KeyPaths<any, never>>().type.toBeAssignableTo<never>()
expect<KeyPaths<ExampleObject, any>>().type.toBeAssignableTo<never>()
expect<KeyPaths<ExampleObject, unknown>>().type.toBeAssignableTo<never>()
expect<KeyPaths<any, any>>().type.toBeAssignableTo<never>()