Skip to content
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

Continuing #17110 - Given generic W extends { x: A } should be able to use keyof W['x'] to index w.x #33181

Open
timhwang21 opened this issue Sep 1, 2019 · 2 comments
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript

Comments

@timhwang21
Copy link

timhwang21 commented Sep 1, 2019

TypeScript Version: [email protected]

Search Terms: tagged disjoint union generic

This issue stems from a question I asked on StackOverflow that @jcalz generously researched for me. I adapted his example to be a closer parallel to the example given in #17110.

Code

interface A { a: string; }

interface W {
    x: A
}

function foo<W1 extends W>(w: W1, k: keyof W1['x']) {
  w.x[k]; // Type 'keyof W1["x"]' cannot be used to index type 'A'.

  const x: W1['x'] = w.x; // Okay
  x[k] // Okay
}

Expected behavior:

Same as #17110. However, unlike #17110, W['x'] is only A instead of A | B | undefined. The explanation given as to why #17110 was not a bug was:

The constraint of keyof W1["x"] is keyof (A | B), which simplifies to keyof A & keyof B, which is never (because there are no common properties).

However, here keyof W1['x'] is keyof A which is not never.

Actual behavior:

Same as #17110.

Playground Link: http://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgILIN7LgLmQZzClAHMBuZAXwChrRJZEUB1Ta5D5ADz1WpuowAriARhgAexDIYEiQB5mARmQQukEABN8yZgD4AFAHc8ygDTIA1nksQAnhJi6lAbQDkXNwF0AlGw5GAHRcLpZeFAD0EcgAKnYADihutg5Oyi4ARFwZXm7ICHAgIBJgyABGKEL4EJrIYBLIoJpqdQlJqG6BtBwIUoTcpq4e3sgAvMhBXJHRAPKWcHbs3KFeyFHIcwv8QA

Related Issues: #17110

@jack-williams
Copy link
Collaborator

Property access and element access return the corresponding property type of the constraint, so w.x and w['x'] have type A, this is why the the access with k fails. Once you fall back to something concrete you can't later index with something generic.

The access x[k] works because it uses the declared type which is a generic indexed access type which has been sufficiently deferred, therefore retaining its 'generic-ness'.

I think the only approach that might solve this is to synthesise more indexed access types for property access expressions, perhaps under certain conditions such as being part of larger chain of property access where the outer keys are generic.

Feels like a design limitation, but I'm not certain.

@sandersn
Copy link
Member

sandersn commented Sep 3, 2019

Under the current design, it is. I think we might have the machinery to cheaply switch over from w.x: A to w.x: W1['x'] at this point, but it sounds like a breaking change. To make it happen, we would need

  1. At least a prototype implementation.
  2. An idea of how breaky the change is, as measured by running on the user/RWC/docker/DefinitelyTyped test suites.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants