The Problem: I want to write a function that takes an object and the name of a property as parameters. What I want to achieve is that only property names of properties with a specific type are accepted.
Example: In a person object I have fields name:string and age:number, my function should then only be able to be called with the parameters (person, 'name'). This can be achieved by creating this type:
export type OnlyPropertiesWithSpecificType<TYPE, T> = {
[K in keyof T]: T[K] extends TYPE ? K : never;
}[keyof T];
When accessing the property inside the function the type of the property's values should be constrainted like this:
type Person = {
name: string;
age: number;
};
function somePersonFunction(obj: Person, param: OnlyPropertiesWithSpecificType<string, Person>): string {
return obj[param]; // works, obj[param] is of type 'string'
}
However when I try to generify the function, it is no longer type constrainted:
function someGenericFunction<T>(obj: T, param: OnlyPropertiesWithSpecificType<string, T>): string {
return obj[param]; // doesn't work: "TS2322: Type 'T[{ [K in keyof T]: T[K] extends string ? K : never; }[keyof T]]' is not assignable to type 'string'."
}
This is confusing, because the compiler still only accepts property names belonging to properties of type 'string' as param:
someGenericFunction(person, 'name'); // works
someGenericFunction(person, 'age'); // doesn't work
What I tried:
- TS versions 3.4.5 and 4.1.2.
- Various variations on T, i.e. T extends object
I created a sandbox with the above example: https://codesandbox.io/s/typescript-forked-ypy0b
How do I solve this problem?