TypeScript Version: master (b2bae85)
Search Terms: mapped type parameter member index signature constraint constrained union
Code (with noImplicitAny)
function foo1<K extends string>(arg: { [P in K]: string }) {
// Actual: Error: Element implicitly has an 'any' type because type '{ [P in K]: string; }' has no index signature.
return arg["test"];
}
function foo2<K extends string | number>(arg: { [P in K]: string }) {
// Actual: No error
return arg["test"];
}
function foo3<K extends "foo">(arg: { [P in K]: string }) {
// Actual: Error: Property 'foo' does not exist on type '{ [P in K]: string; }'.
return arg.foo;
}
function foo4<K extends "foo" | "bar">(arg: { [P in K]: string }) {
// Actual: No error
return arg.foo;
}
Expected behavior: Consistent behavior between foo1 and foo2 and between foo3 and foo4.
Actual behavior: As marked.
Playground Link: link (with noImplicitAny)
Related Issues: None found.
Looks like the cause is that this line in resolvedMappedTypeMembers in the checker is using getApparentType, which changes either string or "foo" to String (which doesn't generate an index signature) but leaves unions alone. What was the thinking here??
const keyType = constraintType.flags & TypeFlags.InstantiableNonPrimitive ? getApparentType(constraintType) : constraintType;