Reputation: 24527
I have the following type with 2 generic parameters:
type Result<INPUT, SPEC> = ...
The concrete type of Result
depends on the various combinations of INPUT
and SPEC
.
How it should work:
if(INPUT extends {[key: string]: any}) {
if(SPEC extends {[key: string]: any}) {
Result = {[key in keyof INPUT]: SPEC[key] !== undefined
? Result<INPUT[key], SPEC[key]>
: true
}
} else {
// ...
}
} else {
// ...
}
In words:
INPUT
and SPEC
are objects, then Result
should be an object with the keys of INPUT
.INPUT
: Check if SPEC
contains the same keytrue
, then the value for this key is Result<INPUT[key], SPEC[key]>
false
, then the value for this key is true
Additional Information:
INPUT
and SPEC
are objects, then SPEC
is a subset of INPUT
. This means: INPUT
can be { foo: 42, bar: 42 }
, but SPEC
is allowed to only contain foo
or bar
or both or be empty.Is this somehow possible with TypeScript?
Upvotes: 1
Views: 45
Reputation: 249556
Based on your description, this type should do the trick:
export type Result<INPUT, SPEC> = INPUT extends object ? SPEC extends object ? {
[K in keyof INPUT]: SPEC extends Record<K, infer SPECK> ?
Result<INPUT[K], SPECK> :
true
} : never : never;
// r is { foo: true; bar: never; goo: { a: never; b: true; }; }
type r = Result<{
foo: number,
bar: string,
goo: { a: number; b: string }
}, { bar: number, goo: { a: number }}>
The part you were probably missing is SPEC extends Record<K, infer SPECK>
, this tests if the type extends a record with the key K
and puts the type of that key in SPECK
.
You were not explicit about what happens on the else branches (if either type parameters is not an object, so I put never
there, but you can customize as you need)
Let me know if I did not get it 100% right, we can make adjustments as needed.
Upvotes: 2