microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.75k stars 12.46k forks source link

Generic extending union type inference error #47233

Open orange4glace opened 2 years ago

orange4glace commented 2 years ago

Bug Report

I am not sure this is intentional or not.

🔎 Search Terms

TS2322 generic union

🕗 Version & Regression Information

4.5.4

⏯ Playground Link

https://www.typescriptlang.org/play?#code/C4TwDgpgBAGlC8UDeUAeAuKA7ArgWwCMIAnAbigF8AoUSKATQWShE10JPOtuhkcTgAfBqSo1w0AOIAeACpQIqYBCwATAM6x6APiZIqUKAHM2+ImSoUoAMiizRVAGY4sAY2ABLAPZYozt3IKSioaWtoAFACUzFAGUK4+6sBomPqGhiZQAAxxVrYwooYJWElorMhxGZg5hnlQ4UIMkYXxicnAqZXG1bk2dg5FbcYA+gDuHsAAFsMYUDJ8uoioLQD0K1AA8gDSccWlRmMT06jl8zpMJ6vr27tDB+NTwx1z0gtMwFd2AMoATADMPx+liAA

💻 Code

type X = { x: number; }
type Y = { y: number; }
type XY = X | Y;

type G<T extends XY> = {
  g: number;
} & T;

function func<T extends XY>() {  
  const x: {
    g: 0
  } & X;
  const xy: {
    g: 0
  } & (X | Y);
  const t: {
    g: 0
  } & T;

  const g_with_x: G<XY> = x;
  // OK
  const g_with_xy: G<XY> = xy;
  // OK
  const g_with_t: G<XY> = t;
  // TS2322
}

🙁 Actual behavior

TS2322 occurs

🙂 Expected behavior

It should not, maybe?

orouz commented 2 years ago

i think it should be const g_with_t: G<T> = t; ?

because G<XY> isn't the same as G<T>, which can be narrower

orange4glace commented 2 years ago

because G<XY> isn't the same as G<T>, which can be narrower

I think G<T> to G<XY> is broadening 🤔 Is there any case that G<T> to G<XY> is narrowing?

orouz commented 2 years ago

yeah, looking at this again, i think it should be possible to widen the constrained T back to XY

i kinda read your example like this, which isn't the same

function func<T extends XY>(): G<T> {
  return {} as G<XY>; // slightly different TS2322
}