Skip to content

Probable bug: Can't infer an invariant generic on contravariant position when involving another genericΒ #45255

Closed
@devanshj

Description

@devanshj

Bug Report

πŸ”Ž Search Terms

invariant generic, contravariant inference
Maybe related or perhaps because of the same design limitation mentioned in #44999

πŸ•— Version & Regression Information

Tested with 4.3.5

⏯ Playground Link

Playground

πŸ’» Code

declare const d: <T, U>(_: { v: T, m: (t: T) => U, f: (u: U) => void }) => void
declare const a: "a"
declare const b: "b"

d({
  v: a,
  m: t => t,
  f: u => {
    let test1: "a" = u // Type 'unknown' is not assignable to type '"a"'.
  }
})

d({
  v: a,
  m: (t: "a") => t,
  f: u => {
    let test2: "a" = u
  }
})

d({
  v: a,
  m: _ => b,
  f: u => {
    let test3: "b" = u // Type 'unknown' is not assignable to type '"b"'
  }
})

d({
  v: a,
  m: () => b,
  f: u => {
    let test4: "b" = u
  }
})

πŸ™ Actual behavior

In 1st and 3rd function call U gets inferred to unknown

πŸ™‚ Expected behavior

In 1st function call U should get inferred to "a" and in 3rd function call U should get inferred to "b".

Clearly the contravariant position of U in m seems to be a problem because if we annotate it (as done in 2nd call) or omit it (as done in 4th call) it gets inferred to what is expect and there are no error.

A real world use case:

declare const branch:
  <T, U extends T>(_: { test: T, if: (t: T) => t is U, then: (u: U) => void }) => void

declare const x: "a" | "b"

branch({
  test: x,
  if: (t): t is "a" => t === "a",
  then: u => {
    let test1: "a" = u // Type '"a" | "b"' is not assignable to type '"a"'
  }
})

branch({
  test: x,
  if: (t: "a" | "b"): t is "a" => t === "a",
  then: u => {
    let test2: "a" = u // compiles
  }
})

Metadata

Metadata

Assignees

No one assigned

    Labels

    Fix AvailableA PR has been opened for this issueFixedA PR has been merged for this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions