Reputation: 1823
I'm playing around with conditional types and trying to get this this to validate. Interestingly, the test() function does validate if I pass "val" as the parameter, and fails if I pass "name" ...which is the expected behavior. However, Typescript apparently doesn't think o[p] can be relied on to be a number, and throws this:
Operator '+=' cannot be applied to types 'number' and 'T[{ [K in keyof T]: T[K] extends number ? K : never; }[keyof T]]'.
Am I misunderstanding the usage somehow? I thought 'never' would prohibit any parameters that were not explicitly a number...
class Test {
public static SumParam<T>
(t: T[], p:{ [K in keyof T]: T[K] extends number ? K : never }[keyof T]): number {
let n:number = 0;
for (let o of t) {
n += o[p]; //Operator '+=' cannot be applied to types 'number' and 'T[{ [K in keyof T]: T[K] extends number ? K : never; }[keyof T]]'.
}
return (n);
}
public test(): void {
Test.SumParam(
[{ name: "alice", val: 3 },
{ name: "bob", val: 4 }],
"val"); //validates
Test.SumParam(
[{ name: "alice", val: 3 },
{ name: "bob", val: 4 }],
"name"); //Argument of type '"name"' is not assignable to parameter of type '"val"'.
}
}
The fact that the compiler narrows and recognizes that 'val' is the only enumerable property extending number ...doesn't that imply that the conditional syntax is working...?
Upvotes: 2
Views: 396
Reputation: 21380
I bit other error for name
, but in general it works fine:
class Test {
public static SumParam<K extends string, T extends { [key in K]: number }>(t: T[], p: K): number {
let n:number = 0;
for (let o of t) {
n += o[p];
}
return (n);
}
public test(): void {
Test.SumParam(
[{ name: "alice", val: 3 },
{ name: "bob", val: 4 }],
"val"); //validates
Test.SumParam(
[{ name: "alice", val: 3 },
{ name: "bob", val: 4 }],
"name"); // Type 'string' is not assignable to type 'number'.
}
}
Upvotes: 0
Reputation: 249476
Typescript will not be able to follow conditional types that still have unresolved type parameters in them. As such it will not be able to know that o[p]
is of type number.
If you don't mind having the error on the items in the array, you can type the function in a way that allows typescript to know o[p]
is number:
class Test {
public static SumParam<T extends Record<K, number>, K extends keyof T>
(t: T[], p: K): number {
let n:number = 0;
if (!t) return (n);
for (let o of t) {
n += o[p]; //ok.
}
return (n);
}
public test(): void {
Test.SumParam(
[{ name: "alice", val: 3 },
{ name: "bob", val: 4 }],
"val"); //ok, no error here
Test.SumParam(
[{ name: "alice", val: 3 }, // Type 'string' is not assignable to type 'number'.
{ name: "bob", val: 4 }], // Type 'string' is not assignable to type 'number'.
"name");
}
}
Upvotes: 3