Reputation: 32176
I'm trying to create a type that will recursively exclude keys from one type if they do not appear in another. For example, given the two types:
type TargetType = {a: true, b: {c: true, d: true}};
type InputType = {a: string, b: { c: boolean, d: number, e: string }, f: number};
I want to create some generic type PickMatchedKeys<T, U>
such that
PickMatchedKeys<InputType, TargetType> = {a: string, b: { c: boolean, d: number }}
Anyone have an idea of how to accomplish this? Here is my best attempt so far:
type PickMatchedKeys<T, U> = {
[K in keyof T]: K extends keyof U ? PickMatchedKeys<T[K], U[K]> : never;
}
This works alright, but the problem is that the keys f
and b.e
still exist in PickMatchedKeys<InputType, TargetType>
, but have type never
. Ideally those keys would not be present in the final type at all.
Upvotes: 2
Views: 692
Reputation: 328186
Why not something like this:
type PickMatchedKeys<T, U> = {
[K in (keyof T) & (keyof U)]:
T[K] extends object ? PickMatchedKeys<T[K], U[K]> : T[K];
}
You don't really need conditional types to restrict the keys to those which are common to both T
and U
, since you can just intersect the key types. The only thing you need to do is make sure not to drill down into primitives; that's where the T[K] extends object
part comes in. You should decide if you want some other criterion (e.g., do something special with arrays) but that's the basic plan.
Let's examine it:
type TestIt = PickMatchedKeys<InputType, TargetType>;
declare const z: TestIt;
z.a // string
z.b.c // boolean
z.b.d // number
z.b.e // error
z.f // error
Looks good to me. Hope that helps; good luck!
Upvotes: 4