feat(typescript-types): Adapt Get to KeyPaths and KeyPath changes

This commit is contained in:
T. R. Bernstein
2025-07-29 00:41:00 +02:00
parent eba47b51bd
commit 9cb4bc2f06
2 changed files with 47 additions and 32 deletions

View File

@@ -1,25 +1,30 @@
import type { If } from './if.js'
import type { KeyPath } from './key-path.js' import type { KeyPath } from './key-path.js'
import type { KeyPaths } from './key-paths.js' import type { NonContainerType } from './non-container-type.js'
import type { KeyPaths, KeyPaths_Options } from './key-paths.js'
type FilterUndefined<T> = T extends undefined ? never : T type ExtractFromForKey<Obj, Rest, ResultType = never> = Obj extends unknown
type FilterNull<T> = T extends null ? never : T ? never
type FilterUndefinedAndNull<T> = FilterUndefined<FilterNull<T>> : Obj extends undefined
? never
: Obj extends NonContainerType
? Obj | ResultType
: GetByKeyPath<Obj, Rest, ResultType>
type ExtractFromForKey<Obj, Key, Rest> = Key extends keyof Obj type GetByKeyPath<Obj, Keys, ResultType = never> = Keys extends []
? Obj[Key] extends Record<PropertyKey, unknown> ? Obj
? GetByKeyPath<Obj[Key], Rest> : Keys extends [infer Key, ...infer Rest]
: Obj[Key] ? Key extends keyof Obj
: Key extends keyof FilterUndefinedAndNull<Obj> ? ExtractFromForKey<Obj[Key], Rest, ResultType>
? FilterUndefinedAndNull<Obj>[Key] | undefined : Key extends `${infer Key}?`
: undefined ? Key extends keyof Obj
? ExtractFromForKey<Obj[Key], Rest, ResultType | undefined>
: never
: never
: never
type HasNoMoreKeys<K> = K extends [] ? true : false export type Get<
O,
type GetByKeyPath<Obj, Keys> = If< P extends KeyPaths<O, Options, Filter>,
HasNoMoreKeys<Keys>, Options extends KeyPaths_Options = {},
Obj, Filter = null | undefined
Keys extends [infer Key, ...infer Rest] ? ExtractFromForKey<Obj, Key, Rest> : never > = GetByKeyPath<O, KeyPath<P>>
>
export type Get<O extends object, P extends KeyPaths<O>> = GetByKeyPath<O, KeyPath<P>>

View File

@@ -1,19 +1,29 @@
import type { Get } from '@/get.js' import type { Get } from '@/get.js'
import { expect } from 'tstyche' import { expect } from 'tstyche'
interface Example1 { interface ExampleObject {
requiredKey: number nullvalue: null
optionalKey?: number simplevalue: string
unknownNonOptionalKey: unknown unknownKey: unknown
undefinedNonOptionalKey: undefined
neverKey: never neverKey: never
subkey: { undefinedKey: undefined
undefinedOptionalKey?: undefined
optionalKey?: string
objectKey: {
name: string name: string
age: number age?: number
} }
optionalObjectKey?: {
name: string
age?: number
}
arrayKey: [{ name: string; age: number }, 1]
optionalArrayKey?: [{ name: string }, { age?: number }]
} }
expect<Get<Example1, 'requiredKey'>>().type.toBe<number>() // type T = any extends never ? true : false
expect<Get<Example1, 'optionalKey'>>().type.toBe<number | undefined>() // type A = Get<ExampleObject, 'simplevalue'>
expect<Get<Example1, 'subkey.age'>>().type.toBe<number>() expect<Get<ExampleObject, 'simplevalue'>>().type.toBe<string>()
expect<Get<Example1, 'unknownNonOptionalKey'>>().type.toBe<unknown>() expect<Get<ExampleObject, 'optionalObjectKey?.name', {}, never>>().type.toBe<string | undefined>()
expect<Get<ExampleObject, 'optionalObjectKey?.age?', {}, never>>().type.toBe<number | undefined>()
expect<Get<ExampleObject, 'optionalArrayKey?.0.name', {}, never>>().type.toBe<string | undefined>()