Closed
Description
TypeScript Version: Version 3.3.0-dev
Search Terms: string indexer generic mapped type assignable
Code
This seems like a regression (if it is a bug). I get the expected behaviour on the playground 3.1.
function tester<K extends 'a'>(x: Record<K, number>, y: { [x: string]: number }) {
x = y; // no error: not expected
y = x; // no error: expected
}
function tester2(x: Record<'a', number>, y: { [x: string]: number }) {
x = y; // error: expected
y = x; // no error: expected
}
Expected behavior:
A string indexer should not be assignable to a mapped type with a generic constraint.
Actual behavior:
String indexer appears to be assignable to generic record type.
Playground Link: playground with expected behaviour
Update. I think this was introduced by #28218.
// A source type T is related to a target type { [P in Q]: X } if Q is related to keyof T and T[Q] is related to X.
if (!isGenericMappedType(source) && isRelatedTo(getConstraintTypeFromMappedType(target), getIndexType(source))) {
const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target));
const templateType = getTemplateTypeFromMappedType(target);
if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {
return result;
}
}
In this instance we have 'a'
is related string
, but a type with a key set of type string
is not guaranteed to have the key a
. When relating keys I think string
and number
should really be bottom types, so a possible fix is to filter them from the source index type:
filterType(getIndexType(source), t => !(t.flags & (TypeFlags.String | TypeFlags.Number)
// and symbol??