Suppose I have the following JS function:
function extractProperty(propName) {
return x => x[propName];
}
Can I type extractProperty
s.t. by Typescript's type inference I get the following:
const x = { first: 1, second: "two" };
const y = { first: [1], second: 2 };
// or any other object having first and second
const a1 = extractProperty("first")(x); // a1 should be of type number
const a2 = extractProperty("second")(x); // a2 should be string
const a3 = extractProperty("first")(y); // a3 should be number[]
const a4 = extractProperty("second")(y); // a4 should be number
const getFirst = extractProperty("first");
// getFirst should be <T> (t: T) => T["first"]
const getSecond = extractProperty("second");
// getSecond should be <T> (t: T) => T["second"]
If rather than a parameter propName
, I had a fixed property name, I could probably do the following:
function extractPropertyFirst ():
<TFirst> (x: { first: TFirst }) => TFirst
or, slightly more in the direction of what I want to achieve,
function extractPropertyFirst ():
<T> (x: T) => T["first"]
Yet how can I make typescript take the argument of the function as the property name?
I have played around with the following approach, yet without success:
function getProperty<K> (propName: K):
<TProp> (t: { [K]: TProp }) => TProp {
return x => x[propName];
}
Typescript does not accept a general K
as the indexing type.
CodePudding user response:
You can make getProperty
work by using {[Key in K]: TProp}
, or equivalently, Record<K, TProp>
for the type of t
, and adding an K extends PropertyKey
constraint:
function extractProperty<K extends PropertyKey>( propName: K):
<TProp>(t: Record<K, TProp>) => TProp {
return (x) => x[propName];
}
const a1 = extractProperty("first")(x);
// type: number
const a2 = extractProperty("second")(x)
// type: string
const a3 = extractProperty("first")(y);
// type: number[]
const a4 = extractProperty("second")(y);
// type: number