I want to use Pick<Type, Keys>
generically, so I could retrieve keys dynamically ONLY if those exist on the provided Type
.
I tried creating a type GenericPick<T extends Partial<PropertyType>> = Pick<Type, Keys>
but, probably due to the Partial<Type>
type, it returns Keys
specified in Pick<Type, Keys>
even if they do not exist on the provided Type
.
The only way I’ve been able to make this work was by using Conditional Types where I have to validate every possible property with Type extends Pick<Type, Keys>
which make the creation of the type seems very boilerplate.
My question is, is there a better way to use generic Pick<Type, Keys>
to avoid using Conditional Types?
Here is an example to reproduce what I’m trying to do…
interface Properties {
name: string;
animal: true;
plant: true;
fly: boolean;
swim: boolean;
walk: boolean;
}
type Bird = Pick<Properties, 'name' | 'animal' | 'fly'>;
type Fish = Pick<Properties, 'name' | 'animal' | 'swim'>;
type Dog = Pick<Properties, 'name' | 'animal' | 'walk'>;
type Plant = Pick<Properties, never>;
// this works
export type ConditionalPick<T extends Partial<Properties>> =
T extends Pick<Properties, 'name' | 'animal' | 'fly'>
? Pick<Properties, 'name' | 'animal' | 'fly'>
: T extends Pick<Properties, 'name' | 'animal' | 'swim'>
? Pick<Properties, 'name' | 'animal' | 'swim'>
: T extends Pick<Properties, 'name' | 'animal' | 'walk'>
? Pick<Properties, 'name' | 'animal' | 'walk'>
: undefined
const bird: ConditionalPick<Bird> = {
name: 'coco',
animal: true,
fly: true,
};
const fish: ConditionalPick<Fish> = {
name: 'nemo',
animal: true,
swim: true,
};
const dog: ConditionalPick<Dog> = {
name: 'rex',
animal: true,
walk: true,
};
// Good: we cannot assign 'animal' property
const plant: ConditionalPick<Plant> = undefined;
// this doesn't work
export type GenericPick<T extends Partial<Properties>> = Pick<T, 'name' | 'animal' | 'fly' | 'swim' | 'walk'>
// bad: those properties don't exist on type Plant
const plantTwo: GenericPick<Plant> = {
name: 'some plant',
animal: false,
fly: false,
swim: false,
walk: false,
}
Link to TypeScript playground