microsoft / TypeScript

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

Extend {} type checking failure #55546

Closed aabeborn closed 1 year ago

aabeborn commented 1 year ago

🔎 Search Terms

type checking on extending generics

🕗 Version & Regression Information

⏯ Playground Link

No response

💻 Code

export interface ItemDef<T extends {}, K extends keyof T> {
  id: keyof T extends string ? keyof T : never;
  subItem?: keyof T;
  children?: T[K] extends Array<infer U> ? ItemDef<U extends {} ? U : never, keyof U> : ItemDef<T[K], keyof T[K]>;
  render: (props: RenderPropsItem<T>) => ReactNode;
  renderBody?: (props: RenderPropsItem<T>) => ReactNode;
}

interface RenderProps {
  id: string;
  [key: string]: unknown;
}

export type RenderPropsItem<T> = T & RenderProps;

export interface RenderItem {
  id: string;
  data: unknown;
  render: (...args: unknown[]) => ReactNode;
  renderBody?: (...args: unknown[]) => ReactNode;
  subItems?: RenderItem[];
  isExpanded?: boolean;
  isExpandable?: boolean;
  toggleExpanded: () => void;
}

🙁 Actual behavior

In the new 5.2 version the children property on type checking returns an error

Type error: Type 'T[K]' does not satisfy the constraint '{}'.
   Type 'T[keyof T]' is not assignable to type '{}'.
    Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'.
      Type 'T[string]' is not assignable to type '{}'.

on line children?: T[K] extends Array<infer U> ? ItemDef<U extends {} ? U : never, keyof U> : ItemDef<T[K], keyof T[K]>;

while in the previous version the type check was fine

🙂 Expected behavior

Not sure if it was an error on previous version (5.1.6) or it's a regression. If a regression to work fine

Additional information about the issue

No response

Andarist commented 1 year ago

Bisected it to this diff which clearly points to https://github.com/microsoft/TypeScript/pull/54845 .

This code didn't typecheck with 5.0 and the fact that it did typecheck ok with 5.1 was a bug. This works as intended.

You need to find a way to add the appropriate constraint to T[K] there. I see that you are already doing this ItemDef<U extends {} ? U : never, keyof U> in the array-related branch of this conditional type. A similar thing would do the trick in the branch that doesn't typecheck today: ItemDef<T[K] extends {} ? T[K] : never, keyof T[K]>. That said, I'd probably try to improve the T's constraint on your place.

typescript-bot commented 1 year ago

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