I have a function named getPropertyReference
that returns a reference of a property in an object. It's mostly for my sanity to prevent typing this.object.myNestedObject.property = ...
over and over.
Here's the complete function:
export function getPropertyReference(object: {[key: PropertyKey]: any}, prop: PropertyKey): any {
return {
get value(): any {
return object[prop];
},
set value(to: any) {
object[prop] = to;
}
}.value; // return the getters and setters without having to access ref.value
}
Usage goes something along the lines of
const ref = getPropertyReference(this.object.myNestedObject, "foo");
ref = 4;
console.log(ref); // 4
console.log(this.object.myNestedObject.foo); // 4
// etc
That code works fine. However, it has a return type of any
, and it would be much nicer to get a return type of object[prop]
. My code looks like this:
export function getPropertyReference<O = {[key: PropertyKey]: any}, K = keyof O>(object: O, prop: K): O[K] {
// same code here
}
Typescript complains about this here. "Type 'K' cannot be used to index type 'O'." How can I fix this?
CodePudding user response:
@Thomas That's exactly how I interpreted it as well. A higher order function which creates and returns a closure — functional get (0 args) and set (1 arg) — would work, too
OK, this is possible:
function getPropertyReference<T extends object, K extends keyof T>(object: T, prop: K) {
function ref(): T[K];
function ref(value: T[K]): void;
function ref() {
if (arguments.length === 0) {
return object[prop];
}
object[prop] = arguments[0];
return; //Not all code paths return a value.(7030)
}
return ref;
}
const example = { name: "bob", age: 12 };
let age = getPropertyReference(example, "age"); // number
console.log(age());
age(18);
console.log(age());
CodePudding user response:
You're very close with the last type you tried. Problem is just that you did =
in the generic definition, when you should have used extends
. For example, K = keyof O
means K
can be absolutely any type, but will default to keyof O
if no type is supplied. Instead, it needs to be K extends keyof O
, which will restrict K
to the keys of the object.
export function getPropertyReference<
O extends { [key: string]: any },
K extends keyof O
>(object: O, prop: K): O[K] {
return {
get value(): O[K] {
return object[prop];
},
set value(to: O[K]) {
object[prop] = to;
},
}.value;
}
const example = { name: "bob", age: 12 };
let age = getPropertyReference(example, "age"); // number
let error = getPropertyReference(example, "doesNotExist"); // compile time error