microsoft / TypeScript

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

Type inference destructure object #50684

Open herrlegno opened 2 years ago

herrlegno commented 2 years ago

Bug Report

Typescript seems to not be able to infer correctly a rest object type.

I've found a workaround for it by nesting the value (in playground)

🔎 Search Terms

Destructuring

🕗 Version & Regression Information

Tested in 4.5.5, 4.8.2 and next (time of writing = v4.9.0-dev.20220908)

⏯ Playground Link

Playground

💻 Code

type Value = { // This properties should be always inside the dataset, to be able to render the graph
  key: string;
  color: string;
  value: number;
};

export type GraphDataSetType<
  T extends Record<string, unknown> = Record<string, never> // This represents extra data that can be used when rendering the legend for a value
> = (
(Value & T) & {
  legend: JSXElementConstructor<Value & T>
})[];

type Props<T extends Record<string, unknown> = Record<string, never>> = {
  values: GraphDataSetType<T>;
};

/* This doesn't work */
const Component = <T extends Record<string, unknown>>({values}: Props<T>) => values.map(({ legend: CustomLegend, ...props }) => <CustomLegend {...props} />)
                                                                                                                              // ^ Error

🙁 Actual behavior

Throws an error

Type 'Omit<Value & T & { legend: JSXElementConstructor<Value & T>; }, "legend">' is not assignable to type 'IntrinsicAttributes & Value & T'.
  Type 'Omit<Value & T & { legend: JSXElementConstructor<Value & T>; }, "legend">' is missing the following properties from type 'Value': key, color, value

🙂 Expected behavior

Expect to not throw an error as Omit<Value & T & { legend: ... }, "legend" }> === Value & T

herrlegno commented 2 years ago

Also found another bug, but I don't know if it's React types or TypeScript Inference: Playground

andrewbranch commented 2 years ago

Reduced: https://www.typescriptlang.org/play?ts=4.8.2#code/JYWwDg9gTgLgBAJQKYEMDGMA0cDecBSAygBoCiANkiEgHYwDCENAzjFAK4bRwC+cAZlAgg4AciioMogFDSYATzBI4ANRTl2ygLy5pcOAGsk8gFxxWUYDQDmAbj1w0EctDMWrdhwDd1mszXYQACMkKHsee2l+dhoMYCYBAB4AFTgkAA8YWgATZkQkJyhsxPcbbBiDGggAdxoAPjqACgBKXX0nFnh6dlZhABkkaxy4HRjspH4rJGyAQjgUPKIySmo6Rk6OLihEtQ1lADI4ZLr7dqZWNMyoFAAFITARuDGJqdn5vN3NOEPUw7x+CAQMwVKq1XinOCNRLdXogAZDGjZXAAOlRGTYt3ufAA9HVmpEzp1cAJAdhUciJCAIF5pqQrpiIA8+Dp0dc7oyIVCYTB+oNhjhyZTqbT6eywDi8eFpEA

jakebailey commented 2 years ago

50604 looks about the same, in that the error message is sort of the same "omitting something that I intersected in"

Type 'Omit<T & { x: X; }, "x">' is not assignable to type 'T'.
  'T' could be instantiated with an arbitrary type which could be unrelated to 'Omit<T & { x: X; }, "x">'.

That one had a workaround (and might be correct?), but it seems like there's a bug here.

andrewbranch commented 2 years ago

50604 is definitely working as intended. If T is instantiated with an object that also has a property x, the result of Omit<T & { x: X }, "x"> will not be assignable to T.

Likewise, the pattern in the OP here (and my reduced case) should be an error, since T can be instantiated with an object including the legend property (or foo in my reduced case), but the elaboration in the error message is nonsensical:

Type 'Omit<Value & T & { foo: unknown; }, "foo">' is missing the following properties from type 'Value': key, color, value(2322)

This makes me think that it’s an error for a completely incorrect reason.

andrewbranch commented 2 years ago

While I think something is definitely awry here, I’m going to bump it to the backlog since it shouldn’t compile and it doesn’t.

herrlegno commented 2 years ago

Never thought of the case where T could be instanciated with the same Omitted properties, that's correct. Nevertheless in that case the error should be something like #50604, so maybe is something else. Thank you for the clarification!

Also, could you take a look to the playground linked here?

Also found another bug, but I don't know if it's React types or TypeScript Inference: Playground

Should I make another issue in this repo or should I do it at React Types? I don't know who can be responsible of it. Thank you!

andrewbranch commented 2 years ago

@herrlegno that’s a duplicate of #241 (congrats, you found a three-digit one!)