Issue
Is there some canonical way to type functional shared instantiation in TypeScript, such we can do something like:
const indexableMethods = {
valueAt(index: number) {
return this.array[index]; // Property 'array' does not exist on type '{ valueAt(index: number): any; }'
},
};
function asIndexable<T extends { array: unknown[] }>(object: T) {
return Object.assign(object, indexableMethods);
}
const foo = asIndexable({ array: [1, 2, 3] });
console.log(foo.valueAt(1)) // 2;
One problem seems to be using this.array
in indexableMethods
. I've tried moving the method definitions inside the assigning function, however, I still have a problem with not being to infer the return type of valueAt
properly:
function asIndexable<T extends { array: unknown[] }>(object: T) {
return Object.assign(object, {
valueAt(index: number) {
return object.array[index];
},
});
}
const x = asIndexable({ array: [1, 2, 3] }).valueAt(1) // x: unknown
Adding a generic parameter (asIndexable<T, U extends { array: T[] }>(...)
) does not seem to help either.
Is there any to add functionality to objects like this while retaining type information?
Solution
This code does the trick, where I have specified the return type of valueAt
explicitly, otherwise the inferred return type would be unknown
which is simply the broadest type TS can use in that context:
function asIndexable<T extends { array: unknown[] }>(object: T) {
type V = typeof object["array"][number];
return Object.assign(object, {
valueAt(index: number): V {
return object.array[index];
},
});
}
const a = asIndexable({ array: [1, 2, 3], b: 1 });
// const a: { array: number[]; b: number;} & { valueAt(index: number): number; }
const x = asIndexable({ array: [1, 2, 3], b: true }).valueAt(1);
// const x: number
const y = asIndexable({ array: [1, 2, 3], b: true }).array[1];
// const y: number
const z = asIndexable({ array: ["1", "2", "3"], b: 1 }).valueAt(1);
// const z: string
const e = asIndexable({ array: ["1", "2", 3], b: 1 }).valueAt(1);
// const e: string | number
Answered By - Julio Di Egidio
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.