Skip to content

Infer IndexedAccess type when accessing property of type variable #30938

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
ajafff opened this issue Apr 15, 2019 · 3 comments · Fixed by #31000
Closed

Infer IndexedAccess type when accessing property of type variable #30938

ajafff opened this issue Apr 15, 2019 · 3 comments · Fixed by #31000
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@ajafff
Copy link
Contributor

ajafff commented Apr 15, 2019

TypeScript Version: 3.5.0-dev.20190413

Search Terms:

Code

nightly version 20190413 (probably #30769?) broke code that looked like this

function fn<T extends {elements: Array<string>} | {elements: Array<number>}>(param: T, cb: (element: T['elements'][number]) => void) {
    cb(param.elements[0]);
}

Expected behavior:

Passes type checking, type of param.elements[0] is inferred as T['elements'][number].

Actual behavior:

Argument of type 'string | number' is not assignable to parameter of type 'T["elements"][number]'.
  Type 'string' is not assignable to type 'T["elements"][number]'.ts(2345)

Related Issues:
#30769

@jack-williams
Copy link
Collaborator

jack-williams commented Apr 15, 2019

I guess this is a fallout of the new behaviour that ignores index signatures on constrained variables when assigning to? It feels like this should work, but would require deferring the simplification of T['elements'][number] to string | number. Maybe in the relation check it's too eagerly fetching the source constraint?

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Apr 15, 2019
@ahejlsberg
Copy link
Member

ahejlsberg commented Apr 17, 2019

This is indeed caused by #30769. A simpler example that exhibits the same issue:

function fn2<T extends Array<string>>(param: T, cb: (element: T[number]) => void) {
    cb(param[0]);  // Error
}

The key scenario we want to handle is this:

function fn3<T extends { [key: number]: string }>(param: T, cb: (element: T[number]) => void) {
    cb(param[0]);  // Error
}

Here, the only thing that the constraint validates is that the numerically named properties of T (if any) are of type string. But a type argument for T can originate in an object literal type that doesn't actually have a numeric index signature. So here the new rule seems very reasonable.

Now, the constraint Array<string> of course validates much more than { [key: number]: string } and it is highly unlikely (albeit possible because of structural typing) that the argument isn't actually an array. So the new rule does indeed seem like overkill here.

Maybe the new rule should be in effect only when the target has an index signature and no other members.

@ahejlsberg
Copy link
Member

On further reflection, I think the right approach here is to only ignore string index signatures coming from constraints (as opposed to ignoring both string and numeric index signatures). The examples motivating the new rule all had string index signatures and really all were related to dictionary-like uses of objects.

@ahejlsberg ahejlsberg added Bug A bug in TypeScript Fixed A PR has been merged for this issue and removed Needs Investigation This issue needs a team member to investigate its status. labels Apr 17, 2019
@ahejlsberg ahejlsberg added this to the TypeScript 3.5.0 milestone Apr 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants