feat(typescript-types): Remove optionality of keys in Assign

This commit is contained in:
T. R. Bernstein
2025-07-15 08:10:24 +02:00
parent eac7768bfb
commit 9700b7d46d
2 changed files with 36 additions and 13 deletions

View File

@@ -1,9 +1,15 @@
import type { OptionalKeysOf } from './optional-keys-of.js' import type { OptionalKeysOf } from './optional-keys-of.js'
type GetNonOptionalValueAt<Obj, Key, Default> = Key extends keyof Obj
? undefined extends Obj[Key]
? Default
: Obj[Key]
: Default
export type Assign< export type Assign<
Shape extends object, Shape extends object,
Defaults extends Pick<Required<Shape>, OptionalKeysOf<Shape>>, Defaults extends Pick<Required<Shape>, OptionalKeysOf<Shape>>,
Obj extends Shape Obj extends Shape
> = { > = {
[K in keyof Shape]: K extends keyof Obj ? Obj[K] : K extends keyof Defaults ? Defaults[K] : never [K in keyof Shape]-?: GetNonOptionalValueAt<Obj, K, K extends keyof Defaults ? Defaults[K] : never>
} }

View File

@@ -1,29 +1,46 @@
import type { Assign } from '@/assign.js' import type { Assign } from '@/assign.js'
import { expect } from 'tstyche' import { expect } from 'tstyche'
interface Person { interface OptionsWithRequired {
name: string name: string
tag?: string
age?: number age?: number
} relations?: Array<OptionsWithRequired>
interface Options extends Person {
relations?: Array<Person>
} }
interface DefaultValues { interface DefaultValues {
name: 'Max Mustermann' tag: 'Max Mustermann'
age: 17 age: 17
relations: [] relations: []
} }
expect<Assign<Options, DefaultValues, { name: 'Another Name' }>>().type.toBe<{ expect<Assign<OptionsWithRequired, DefaultValues, { name: 'Another Name' }>>().type.toBe<{
name: 'Another Name' name: 'Another Name'
age?: 17 tag: 'Max Mustermann'
relations?: [] age: 17
relations: []
}>() }>()
expect<Assign<Options, DefaultValues, { name: 'Another Name'; age: 18 }>>().type.toBe<{ expect<Assign<OptionsWithRequired, DefaultValues, { name: 'Another Name'; age: 18 }>>().type.toBe<{
name: 'Another Name' name: 'Another Name'
age?: 18 tag: 'Max Mustermann'
relations?: [] age: 18
relations: []
}>()
interface Options {
tag?: string
age?: number
}
expect<Assign<Options, DefaultValues, {}>>().type.toBe<{
tag: 'Max Mustermann'
age: 17
}>()
interface SpecifiedOptions extends Options {}
expect<Assign<Options, DefaultValues, SpecifiedOptions>>().type.toBe<{
tag: 'Max Mustermann'
age: 17
}>() }>()