I have created a TypeScript curried function which first receives a property name as a string and then the object to get the value of that property from. I have used index type to make sure I get an error whenever I try to access a non-existing property:
export interface Dict {
name: string;
age: number;
}
const prop = <T extends Dict, K extends keyof T>(p: K) => (obj: T): T[K] => obj[p];
prop('name')({name: 'John', age: 45}); // John
prop('name2')({name: 'John', age: 45}); // error...
The last line gives the error:
error TS2345: Argument of type '"name2"' is not assignable to parameter of type '"name" | "age"'.
which is exactly what I want since the property name2 does not exist on the object given as the second argument.
However, when I try to create a safe version using a Maybe monad it gives a similar error:
const safeProp = <T extends Dict, K extends keyof T>(p: K) => (obj: T): Maybe<{}> => compose2(Maybe.of, prop(p))(obj);
The error is on the second argument of the compose2 function: prop(p):
Argument of type 'K' is not assignable to parameter of type '"name" | "age"'.
Which I don't understand since I have declared K extends keyof T which I assumed to be correct since it also works for the prop function.
For reference, the compose2 function:
const compose2 = <A, B, C>(f: (b: B) => C, g: (a: A) => B): ((a: A) => C) => a => f(g(a));
and the relevant part of Maybe monad:
class Maybe<A> {
static of<A>(x: A): Maybe<A> {
return new Maybe(x);
}
...
}
How do I correctly type the safeProp function and why do I need to specify its return type as Maybe<{}> and not Maybe<T[K]>?