Reputation: 60
i have a type with some properties typed string, number, etc..., and i want to omit some properties who's type isn't string.
the Omit<T, U>
generic just omit by property name, but not property type.
for example:
class Person {
name: string;
age: number;
eat(food: Food): void;
walk(miles: number): void;
read(book: Book): void;
}
// =>
type PersonAbility = PickAbility<Person>;
// how can i write a PickAbility<T> generic, results:
type PersonAbility = {
eat(food: Food): void;
walk(miles: number): void;
read(book: Book): void;
}
as the code above.
and i have try this:
type PersonAbility = {
[K in keyof Person]: Person[K] extends (payload: {}) => Promise<{}> ? Person[K] : never
};
// it results:
type PersonAbility = {
name: never;
age: never;
eat: (food: Food) => void;
walk: (miles: number) => void;
read: (book: Book) => void;
}
the codes above set the property not needed to never
, but not remove it.
Upvotes: 2
Views: 1112
Reputation: 329903
The solution here is to get the union of keys corresponding to the property values you want, and then Pick
those. Here's one way to do it:
type KeysMatching<T, V> = {
[K in keyof T]-?: T[K] extends V ? K : never
}[keyof T];
KeysMatching<T, V>
uses a mapped, conditional, and lookup type to find the keys of type T
whose property values are assignable to type V
.
Then we can make PickMatching<T, V>
which just Pick
s those values:
type PickMatching<T, V> = Pick<T, KeysMatching<T, V>>;
And PickAbility<T>
will just use PickMatching
on Function
-valued properties (your example code uses (payload: {}) => Promise<{}>
but none of your Person
methods match that):
type PickAbility<T> = PickMatching<T, Function>;
Let's test it:
type PersonAbility = PickAbility<Person>;
/*
type PersonAbility = {
eat: (food: Food) => void;
walk: (miles: number) => void;
read: (book: Book) => void;
}
*/
Looks good. Hope that help; good luck!
Upvotes: 5