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

Regression in 3.4: Type inference with generic type guard breaks #31086

Closed
timsuchanek opened this issue Apr 24, 2019 · 0 comments · Fixed by #31141
Closed

Regression in 3.4: Type inference with generic type guard breaks #31086

timsuchanek opened this issue Apr 24, 2019 · 0 comments · Fixed by #31141
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@timsuchanek
Copy link
Contributor

timsuchanek commented Apr 24, 2019

TypeScript Version: 3.5.0-dev.20190424

Search Terms:
generic type parameters broken, regression 3.4, type inference for mapped conditional types broken

Code

type UserArgs = {
  select?: boolean
}

type Subset<T, U> = { [key in keyof T]: key extends keyof U ? T[key] : never }

function withBoundary<T extends UserArgs>(args?: Subset<T, UserArgs>): T {
  return null as any
}

const boundaryResult = withBoundary({
  select: true,
})

// In TypeScript@3.3:
/**
 * typeof boundaryResult === {
 *   select: true
 * }
 */

// In TypeScript@3.4 @ TypeScript@next:
/**
 * typeof boundaryResult === UserArgs
 */

function withoutBoundary<T extends UserArgs>(args?: T): T {
  return null as any
}

const withoutBoundaryResult = withoutBoundary({
  select: true,
})

// In TypeScript@3.3:
/**
 * typeof withoutBoundaryResult === {
 *   select: true
 * }
 */

// In TypeScript@3.4 & TypeScript@next:
/**
 * typeof withoutBoundaryResult === {
 *   select: true
 * }
 */

Expected behavior:
I expect the return type of the withBoundary function to actually include the fine-grain information of which concrete boolean value is provided for the select property. It should have type {select: true}.

Actual behavior:
Instead, it's typecasted to UserArgs.

We need this behavior to work because we want to make sure that users of our library only pass in a "subset" and not a superset of the UserArgs type into the withBoundary function. As T extends UserArgs is not sufficient to narrow that down, we use (args?: Subset<T, UserArgs>). This worked in 3.3 and is now broken in 3.4.

Playground Link

Related Issues:

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Apr 24, 2019
@ahejlsberg ahejlsberg added Bug A bug in TypeScript Fixed A PR has been merged for this issue and removed Needs Investigation This issue needs a team member to investigate its status. labels Apr 27, 2019
@ahejlsberg ahejlsberg added this to the TypeScript 3.5.0 milestone Apr 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants