Reputation: 53
I have a filter function working, but I can't for the life of me find out how to write a generic type that communicates this returned data structure:
class Value<T> {
val: T;
constructor(val: T){
this.val = val;
}
get(): T {
return this.val;
}
}
let data = {
foo: new Value(123),
bar: new Value('abc'),
baz: 'xyz'
}
let filter = (obj: Object): any => {
let result: any = {};
for (const [key, val] of Object.entries(obj)) {
if(val instanceof Value) result[key] = val.get();
}
return result;
};
filter(data).foo; // 123
filter(data).bar; // 'abc'
filter(data).baz; // error
I've managed to do some somewhat complex things with generics, but I think this is way beyond my depth. Any help would be greatly appreciated.
Upvotes: 0
Views: 789
Reputation: 33691
I think this is what you're looking for:
type Filtered<T> = {
[K in keyof T as T[K] extends Value<any> ? K : never]: T[K] extends Value<any>
? ReturnType<T[K]['get']>
: never;
};
function filter<T extends Record<string, unknown>>(obj: T): Filtered<T> {
const result = {} as Filtered<T>;
for (const [key, val] of Object.entries(obj)) {
if (val instanceof Value) result[key as keyof typeof result] = val.get();
}
return result;
}
Upvotes: 2