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

Can't infer generic argument, recursive / nested usage #33858

Closed
natew opened this issue Oct 7, 2019 · 4 comments
Closed

Can't infer generic argument, recursive / nested usage #33858

natew opened this issue Oct 7, 2019 · 4 comments
Assignees
Labels
Duplicate An existing issue was already created

Comments

@natew
Copy link

natew commented Oct 7, 2019

TypeScript Version: 3.6.3 and 3.7-beta

Code

const Test = gloss2<{ a: number }>(undefined)

// remove typeof Test and it breaks
// it should infer the { a: number }, but wont
const Test2 = gloss2<{ b: number }, typeof Test>(Test).theme(x => {
  x.a
  x.b
})

type Thing<X> = {
  x: X
  theme: (cb: (x: X) => any) => Thing<X>
}

function gloss2<A, B = any>(
  a?: B,
  b?: A
): Thing<A & (B extends Thing<infer C> ? C : {})> {
  return 0 as any
}

https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=22&pc=1#code/LAKAxg9gdgzgLgAgCoFN4ILwIOYBsIwwBMAPAN4ICGAXAlAK4C2ARigE4IC+AfABT1QAJigBmASygpBASlCgA9PIRsUjCADcUCOAE8ADiggjkaRJSEIxiZisoBrGAqVWEMABYR6uQZagj22m5aFDR0TKwcnAA0CMz0iADu0HCgkLCIqPBEmDj4hKQUzLQMLAHR2vqGxplwfDXSAHRwQYwovAAemNwIZKAICO0NlH0DDcygnLIgoLoGyG4S2CQAGt1YvSD97bTLI82qKLS8YEUIHTvSXVRQOpcY3UgLUEurE3IgIgJgcGLQuQTEEgAQRiACEcuYdHwRpQAPy0UFREbMeEIIGgaS0R6LYEIABkZ3BKHacBQQhg8xxEn8HAAwt1YQhaQhaGRJt0Nv0VHB6GwoAgAAxUCmQt4gIA

Expected behavior:

Test2 should be able to infer the generics from Test, but if you remove the typeof Test argument from the playground above you'll see it can't infer it.

Related Issues:

I believe this may be related to: #30134

But I'm not sure. In this case it doesn't seem very complex at all, yet I've tried this same snippet of code now every possible permutation I could imagine and none of them seem able to work. Really, I've been scratching my head on this one, it seems simple.

@natew natew changed the title Can't infer generic argument, recursive usage Can't infer generic argument, recursive / nested usage Oct 7, 2019
@natew
Copy link
Author

natew commented Oct 7, 2019

I've tried a ton of variations, here's another, note Test2 doesn't pick up Test:

const Test = gloss2<{ a: number }>()
const Test2 = gloss2<{ b: number }>(Test)

interface Thing<X> {
}

function gloss2<A>(a?: any): Thing<A>
function gloss2<B = {}, A = {}>(a?: Thing<A>): Thing<A & B> {
  return 0 as any
}

https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=11&pc=1#code/MYewdgzgLgBAKgU2jAvDA5gGxBCAmAHgG8YBDALhjAFcBbAIwQCcYBfAPgAoBKAWAChQkWImh5UGbLkIl6lGg2ZsuoqH34CAlmCjMAZqWAJ4AC23oCADXYwiA1gIF7qYYFE3hJOfAQCCXUgB+SlIwAE9uSjgzMAt-Jxc3DzAvaQIAIQkiVgAaGF8sjk4gqJi49kjTcz8YADIYdJs7fhgYJgQoaiYUgAYyCDJw+wEgA

Another, using infer:

const Test = gloss2<{ a: number }>()
const Test2 = gloss2<{ b: number }>(Test)

interface Thing<X extends object = {}> {}

type InferProps<A> = A extends Thing<infer X> ? X : {}

function gloss2<
  B extends object = {},
  A extends Thing = Thing
>(a?: A): Thing<InferProps<A> & B> {
  return 0 as any
}

https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=14&pc=1#code/MYewdgzgLgBAKgU2jAvDA5gGxBCAmAHgG8YBDALhjAFcBbAIwQCcYBfAPgAoBKAWAChQkWImh5UGbLkIl6lGg2ZsuoqH34CAlmCjMAZqWAJ4AC23oCADRgIAHrrAATCDBD0AVgmCw0RDjD8BASgATwAHYwBJMD1mAAUmEDCIAgBBdglUm3sEJxc4MzALbViWSwyAfhhrSkCNfj1qMG9NcEkcfAIBGBgAIWyHZ1cPLx8A1gAabpgsu0H8wvQJAvMBLlIKylTuShWigmjShKSU9JgAMj6MommmBChqJjAYAAYyF1IwEIFWASA

@Jessidhia
Copy link

Jessidhia commented Oct 8, 2019

This is affecting the styled-components typings -- the generics seem to not be properly propagated to functions nested inside css templates, causing errors that can't really be fixed as the whole design of the types depend on return type contextual typing.

Here is a real code example that breaks on 3.7.0-beta but did work on 3.6.3:

const PopupRoot = styled.div<{ empty: boolean; isTooltip: boolean }>`
  border-radius: 8px;
  z-index: 1;

  ${props =>
    !props.empty &&
    css`
      min-width: 20px;
      border: 1px solid ${({ theme }) => theme.ui.border.overlay};
    `}
  ${({ theme, isTooltip }) => css`
    background: ${isTooltip ? theme.background.overlayHighContrast : theme.background.clear}
      padding-box;
  `}
`

The error message itself is enormous.

Argument of type '(props: ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | "hidden" | ... 251 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>) => false | FlattenInterpolation<...>' is not assignable to parameter of type 'Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>'.
  Type '(props: ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | "hidden" | ... 251 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>) => false | FlattenInterpolation<...>' is not assignable to type 'InterpolationFunction<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>'.
    Type 'false | FlattenInterpolation<ThemeProps<Theme>>' is not assignable to type 'Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>'.
      Type 'FlattenInterpolation<ThemeProps<Theme>>' is not assignable to type 'Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>'.
        Type 'FlattenInterpolation<ThemeProps<Theme>>' is not assignable to type 'FlattenInterpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>'.
          Types of property 'concat' are incompatible.
            Type '{ (...items: ConcatArray<Interpolation<ThemeProps<Theme>>>[]): Interpolation<ThemeProps<Theme>>[]; (...items: (string | ... 10 more ... | undefined)[]): Interpolation<...>[]; }' is not assignable to type '{ (...items: ConcatArray<Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>>[]): Interpolation<...>[]; (...items: (string | ... 10 more ... | undefined)[]): Interpolat...'.
              Types of parameters 'items' and 'items' are incompatible.
                Type 'ConcatArray<Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>>' is not assignable to type 'ConcatArray<Interpolation<ThemeProps<Theme>>>'.
                  Type 'Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>' is not assignable to type 'Interpolation<ThemeProps<Theme>>'.
                    Type 'FlattenInterpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>' is not assignable to type 'Interpolation<ThemeProps<Theme>>'.
                      Type 'FlattenInterpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>' is not assignable to type 'FlattenInterpolation<ThemeProps<Theme>>'.
                        The types returned by 'concat(...)' are incompatible between these types.
                          Type 'Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>[]' is not assignable to type 'Interpolation<ThemeProps<Theme>>[]'.
                            Type 'Interpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>' is not assignable to type 'Interpolation<ThemeProps<Theme>>'.
                              Type 'FlattenInterpolation<ThemedStyledProps<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "css" | "children" | ... 252 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }, Theme>>' is not assignable to type 'Interpolation<ThemeProps<Theme>>'.

(to reproduce this with @types/styled-components, you need to either define a non-empty Theme interface and use the styled from declare const styled: import('styled-components').ThemedStyledComponentsModule<Theme>['default'], or to augment the DefaultTheme in declare module 'styled-components' { interface DefaultTheme {} } to be non-empty)

This nonsense is also happening:
image

Also strange is that theme has a type in the screenshot, but isTooltip is getting any; despite the generic argument to the outer styled.div specifying the type of isTooltip.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Oct 17, 2019
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.7.1 milestone Oct 17, 2019
@ahejlsberg
Copy link
Member

The issue here is that we don't support partial type inference, i.e. explicitly specifying some type arguments and inferring the rest from the argument list. Once you explicitly specify some type arguments, any remaining omitted ones are always given their declared default value, regardless of the argument list.

We have a proposal to support partial type inference in #26242, so I'll mark this as duplicate.

@ahejlsberg ahejlsberg added Duplicate An existing issue was already created and removed Bug A bug in TypeScript labels Oct 22, 2019
@ahejlsberg ahejlsberg removed this from the TypeScript 3.7.1 milestone Oct 22, 2019
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' 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
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants