Skip to content

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

Closed
@timsuchanek

Description

@timsuchanek

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:

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions