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

Cannot be used to index type in 3.9 (worked in 3.8) #38740

Closed
jasonkuhrt opened this issue May 23, 2020 · 2 comments
Closed

Cannot be used to index type in 3.9 (worked in 3.8) #38740

jasonkuhrt opened this issue May 23, 2020 · 2 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@jasonkuhrt
Copy link

jasonkuhrt commented May 23, 2020

TypeScript Version: 3.9.3

Search Terms:

cannot be used to index type

Code

2536

// A *self-contained* demonstration of the problem follows...
// works in 3.8, fails in 3.9
// Is this a bug in 3.9?
// Nexus (nexusjs.org) depended on this functionality

type Get1<
  A extends any,
  B extends any,
  C extends 'filtering' | 'ordering'
> = A extends keyof Stuff
  ? B extends keyof Stuff[A]
    ? Stuff[A][B][C] // error here
    : never
  : never;

interface Stuff {
  // [k:string]: any               // <-- Putting this here fixes Get1 in TS 3.9
  Blog: {
    // [k:string]: any               // <-- Putting this here fixes Get1 in TS 3.9      
    posts: {      
      filtering: 'a',
      ordering: 'b'
    }
  }
}

Expected behavior:

TS 3.9 supports the same type logic as in 3.8 (see playground repro)

Actual behavior:

Breaks in 3.9 (our context: graphql-nexus/nexus#859)

Playground Link:

link

@ahejlsberg
Copy link
Member

The immediate cause of this is #29571. Previously, a type parameter declared with extends any was treated as just any, which effectively turned off type checking. For example, you could change Stuff[A][B][C] to Stuff[A][42]['elephant'] in your example with no error!

We now treat extends any the same as having no constraint, meaning that things actually get checked. And, in your example A might not include 'Blog' and B might not include 'posts', so there is no guarantee that 'filtering' | 'ordering' is a valid key for Stuff[A][B]. You need to include another check to make it work:

type Get1<
  A extends any,
  B extends any,
  C extends 'filtering' | 'ordering'
> = A extends keyof Stuff
  ? B extends keyof Stuff[A]
    ? C extends keyof Stuff[A][B]
      ? Stuff[A][B][C] // Ok
      : never
    : never
  : never;

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label May 23, 2020
@jasonkuhrt
Copy link
Author

jasonkuhrt commented May 23, 2020

Ahh thanks @ahejlsberg I thought I tried that 🤦.

I also mistakenly thought that TS would statically analyze that Stuff only had filtering and ordering. I guess though the only way for that to happen would be having Stuff come through as a constrained generic.

There's probably an obvious reason TS must/does behave this way, but I don't see it.

Anyways, getting off-topic here.

Thanks again @ahejlsberg!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

2 participants