Skip to content

String Indexer Assignable to Generic Mapped Type #28798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jack-williams opened this issue Dec 2, 2018 · 3 comments
Closed

String Indexer Assignable to Generic Mapped Type #28798

jack-williams opened this issue Dec 2, 2018 · 3 comments
Assignees
Labels
Bug A bug in TypeScript
Milestone

Comments

@jack-williams
Copy link
Collaborator

jack-williams commented Dec 2, 2018

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??
@ahejlsberg
Copy link
Member

@jack-williams I think that is a very sensible suggestion.

@ahejlsberg ahejlsberg added the Bug A bug in TypeScript label Dec 2, 2018
@ahejlsberg ahejlsberg assigned ahejlsberg and weswigham and unassigned ahejlsberg Dec 2, 2018
@sandersn sandersn added this to the TypeScript 3.3 milestone Dec 11, 2018
@jack-williams
Copy link
Collaborator Author

If this is low down on the prio list I'd be happy to give fixing this a go.

@jack-williams
Copy link
Collaborator Author

Fixed here: #30769

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
5 participants