Skip to content

3.5 regression concerning type inference for non-inferable types #31735

Description

TypeScript Version: typescript@3.6.0-dev.20190603

Search Terms:
3.5, infer

Code

// mocked CssProperties type
type CssProperties = { position: "absolute" | "relative" };

type StylesObject<ClassKey extends string> = Record<ClassKey, CssProperties>;
type PropsBasedstyles<ClassKey extends string, Props extends object> = (
  props: Props
) => StylesObject<ClassKey>;
type Styles<ClassKey extends string, Props extends object> =
  | StylesObject<ClassKey>
  | PropsBasedstyles<ClassKey, Props>;

function createStyles<ClassKey extends string, Props extends object>(
  styles: Styles<ClassKey, Props>
): Styles<ClassKey, Props> {
  return styles;
}

const styles = createStyles({
  root: {
    position: "absolute"
  }
});

Expected behavior:
Behavior in 3.4.5
typeof styles = Styles<'root', {}>

Actual behavior:
Behavior in >=3.5.0
typeof styles = Styles<'root', object>

Playground Link:
playground

Related Issues: Did not find any

Notes:

Seems like the playground is still using 3.4.

Usage of this behavior is showcased in https://github.com/eps1lon/ts-inference-3.5/blob/master/index.ts with a fix for 3.5.

Activity

  1. ahejlsberg commented on Jun 3, 2019

    @ahejlsberg
    Member

    This is an effect of #30637, a known breaking change. In your example we make no inferences for the Props type parameter in the call to createStyles. This means we default to unknown, but since that doesn't satisfy the constraint object, we pick object. Previously we'd default to {} which did satisfy the constraint.

  2. eps1lon commented on Jun 4, 2019

    @eps1lon
    ContributorAuthor

    Suspected as much though I wasn't aware how this interacts with non-inferrable types. Thanks for the explanation.

  3. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions