I am attempting to create a function that accepts an array of objects and then one or more parameters that specify the properties which will be used on that array.
For example, either of these:
update([{ name: 'X', percentage: 1, value: 2 }], 'percentage', 'value');
update([{ name: 'X', foo: 1, bar: 2 }], 'foo', 'bar');
Attempt 1:
function update<T extends { name: string }, A extends keyof T, B extends keyof T>(data: T[], a: A, b: B) {
for (const row of data) {
console.log(row.name, row[a] * row[b]);
row[a] = row[a] * row[b];
}
}
- When I try to use
row[a]as a number I get an error because the type isT[A]and seemingly it doesn't know that's a number - When I try to assign a number to
row[a]I getType 'number' is not assignable to type 'T[A]'.(2322)
Attempt 2:
type Entry<A extends string, B extends string> = { name: string } & Record<A | B, number>;
function update<T extends Entry<A, B>, A extends string, B extends string>(data: T[], a: A, b: B) {
for (const row of data) {
console.log(row.name, row[a] * row[b]);
row[a] = row[a] * row[b];
}
}
- This fixes the issue when using
row[a], it seems to be ok with me using it as a number - But I still get
Type 'number' is not assignable to type 'T[A]'.(2322)when trying to assign a number torow[a](or anything for that matter)- Suprisingly, even removing the
{ name: string }fromEntrydoesn't fix this, typescript still won't allow me to assign anything here for some reason
- Suprisingly, even removing the
This seems like a fairly common thing to what to do in JS, but I have no idea how to make Typescript understand it.
Aproperty of something of the formRecord<A, Foo> & Bar, but it's fine with justRecord<A, Foo>. So my suggestion would be to do something like this. Does that work for you or am I missing something?as, because it means you're having to force something because typescript doesn't have enough information - I always try to give typescript that information, if possible.{name: string} & Record<A | B, number>is also aRecord<A, number>but not vice versa, so the latter type is wider than the former. Anyway I'm happy to write up an answer explaining my approach, terminology notwithstanding.