Bug Report
π Version & Regression Information
When did you start seeing this bug occur? From 4.6, in which indexed access inference was improved.
β― Playground Link
Playground link with relevant code
π» Code
interface TypeMap {
"number": number;
"string": string;
"boolean": boolean;
}
type UnionRecord<P extends keyof TypeMap> = { [K in P]:
{
kind: K;
v: TypeMap[K];
f: (p: TypeMap[K]) => void;
}
}[P];
function processRecords<K extends keyof TypeMap>(record1: UnionRecord<K>, record2: UnionRecord<K>) {
record1.f(record2.v); // <-- this is bad
}
processRecords({
kind: "string",
v: "hello!",
f: val => {
console.log(val.toUpperCase());
}
}, {
kind: "number",
v: 123,
f: val => {
console.log(val.toExponential(3));
}
})
π Actual behavior
The code typechecks, but it breaks at runtime: TypeError: val.toUpperCase is not a function.
π Expected behavior
I think record1.f(record2.v); shouldn't be allowed.
π Notes
I understand that the type parameter K isn't behaving like an existential type, so the correct way to type processRecords may be:
function processRecords<
K1 extends keyof TypeMap,
K2 extends keyof TypeMap>(record1: UnionRecord<K1>, record2: UnionRecord<K2>) {
record1.f(record2.v); // <-- now this is an error
}
Playground
I think that the main problem here is that the original definition:
function processRecords<K extends keyof TypeMap>(record1: UnionRecord<K>, record2: UnionRecord<K>) {
record1.f(record2.v);
}
may suggest that the two nodes are related, because this whole feature was added to express correlation between things. But that may not be the case.
And what about a more general one?
function processRecords<K extends keyof TypeMap>(records: UnionRecord<K>[]) {
records.forEach(r => r.f(r.v))
}
Playground
How could I express the fact that each record is related only to itself? I don't even know if its possible to properly type it, I think variadic type arguments would be needed because I need a variable number of Ks, each of which unrelated to others. Not sure. The above typing lets me do bad things as you can see in the playground.
I tried the following, but it is all broken:
type MapKeyofTypeMapToUnionRecord<K extends (keyof TypeMap)[]> =
K extends [infer H extends keyof TypeMap, ...infer REST extends (keyof TypeMap)[]] ?
[UnionRecord<H>, ...MapKeyofTypemapToUnionRecord<REST>] :
[]
function processRecords<K extends (keyof TypeMap)[] | []>(records: MapKeyofTypeMapToUnionRecord<K>) {
records.forEach(r => r.f(r.v)) // broken
}
Playground
Bug Report
π Version & Regression Information
When did you start seeing this bug occur? From
4.6, in which indexed access inference was improved.β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
The code typechecks, but it breaks at runtime:
TypeError: val.toUpperCase is not a function.π Expected behavior
I think
record1.f(record2.v);shouldn't be allowed.π Notes
I understand that the type parameter
Kisn't behaving like an existential type, so the correct way to typeprocessRecordsmay be:Playground
I think that the main problem here is that the original definition:
may suggest that the two nodes are related, because this whole feature was added to express correlation between things. But that may not be the case.
And what about a more general one?
Playground
How could I express the fact that each record is related only to itself? I don't even know if its possible to properly type it, I think variadic type arguments would be needed because I need a variable number of
Ks, each of which unrelated to others. Not sure. The above typing lets me do bad things as you can see in the playground.I tried the following, but it is all broken:
Playground