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

Generic index into two types not seen as assignable, even if the two types are identical for all relevant keys #58905

Closed
jcalz opened this issue Jun 17, 2024 · 4 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@jcalz
Copy link
Contributor

jcalz commented Jun 17, 2024

πŸ”Ž Search Terms

generic, indexed access, supertype

πŸ•— Version & Regression Information

⏯ Playground Link

Playground link

πŸ’» Code

interface Foo {
  a: string,
  b: number
}

interface Bar extends Foo {
  c: boolean
}

function bar<K extends keyof Bar>(k: K, v: Bar[K]) { }

function foo<K extends keyof Foo>(k: K, v: Foo[K]) {
  bar(k, v) // error!
  //     ~
  // Argument of type 'Foo[K]' is not assignable to parameter of type 'Bar[K]'.
  //   Property 'c' is missing in type 'Foo' but required in type 'Bar'.(2345)
}

πŸ™ Actual behavior

bar(k, v) fails because Foo[K] is supposedly not assignable to Bar[K].

πŸ™‚ Expected behavior

bar(k, v) should succeed because Foo[K] is identical to Bar[K]; the only difference between Foo and Bar occurs in a key that K can never be.

Additional information about the issue

This is presumably a design limitation introduced with #30769. And while it's similar to #32693, it's different enough that I'd like to see an official word about it. If there is an existing issue that's the same as this, I didn't find it. Can anyone find one this duplicates? I'm investigating a SO question and while I feel certain I've seen this before, I keep hitting things like #32693 which aren't about generics at all.

On the face of it, if Pick<Foo, KC> and Pick<Bar, KC> are identical, then for generic K extends KC, Foo[K] and Bar[K] should also be identical. Yes, if K turns out to be a union, then you run into the soundness issue that #30769 fixed. We already allow T[K] to be assignable to T[K] if K is generic, so it's not really soundness that's at play here.... we've already decided that generic keys are a way of sidestepping this (I'm looking at you, #47109). I'm guessing it's just not worth the performance hit to check assignability of parts of the source and target object types, so it's a design limitation? Maybe?

@RyanCavanaugh
Copy link
Member

the only difference between Foo and Bar occurs in a key that K can never be.

How does one arrive at this conclusion except via exhaustive analysis of possible values of K? Note that from TS's perspective, this example isn't any different from one with

interface Foo {
  a: string,
  b: number,
}

interface Bar {
  a: string,
  b: number,
  c: boolean
}

@jcalz
Copy link
Contributor Author

jcalz commented Jun 18, 2024

Right, so it's presumably not worth the performance hit to look at K extends keyof Bar and compare Pick<Foo, keyof Bar> to Pick<Bar, keyof Bar> instead of comparing Foo to Bar. Synthesizing the Pick types for every generic assignment would be equivalent to such "exhaustive analysis", I presume?

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jun 18, 2024
@RyanCavanaugh
Copy link
Member

Right, exactly

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Design Limitation" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

3 participants