What I want to achieve
I want to get a subset of specific/predefined properties using Pick<Partial<Type>, Keys>
on a provided Type
. The predefined/specific properties may or may not exist on the provided Type
, but if they don’t we should not be allowed to assign it on the return type.
What I’ve tried
I tried creating a type SubsetPick<T extends Partial<PropertyType>> = Pick<T, Keys>
but, probably due to the Partial<PropertyType>
type, it returns Keys
specified in Pick<T, Keys>
even if they do not exist on the provided Type
.
Example
Here is an example to reproduce what I’m trying to do:
interface Properties {
name: string;
animal: boolean;
plant: boolean;
fly: boolean;
swim: boolean;
walk: boolean;
}
type Bird = Pick<Properties, 'name' | 'animal' | 'fly'>;
// this doesn't work
type SubsetPick<T extends Partial<Properties>> = Pick<T, 'fly' | 'swim' | 'walk'>
// bad: we can assign properties `swim` and `walk` that don't exist on type `Bird`
const birdSubset: SubsetPick<Bird> = {
fly: true,
swim: true, // no error
walk: true, // no error
}
Playground
10
I figured it out inspired by playground examples provided in @jcalz comments…
Using Extract<Type, Union>
it is possible to extract only keys that are assignable to Type
and avoid having unassignable properties in the return type. So instead of using Pick<Type, Keys>
you can construct the return object with the proper type.
interface Properties {
name: string;
animal: boolean;
plant: boolean;
fly: boolean;
swim: boolean;
walk: boolean;
}
type Bird = Pick<Properties, 'name' | 'animal' | 'fly'>;
// this works
type SubsetPick<T extends Partial<Properties>> = {
[P in Extract<keyof T, 'fly' | 'swim' | 'walk'>]: T[P];
};
// good: we can only assign property that exists on type `Bird`
// and that are part of the subset declared in `SubsetPick`
const birdSubset: SubsetPick<Bird> = {
fly: true,
swim: true, // error
}
Playground
2