Skip to content

Unable to unify different uses of same conditional type #23541

Closed

Description

@leighman

TypeScript Version: 2.8.1

Search Terms:
conditional type

Code

const a: TypeFromOption<"configurationA"> = {data: "test"}

const b: TypeFromOption<"configurationB"> = {data: 1}

interface Whatever<T> {
  data: T
}

type Options = "configurationA" | "configurationB"

type TypeFromOption<T extends Options> =
  T extends "configurationA" ? Whatever<string> :
  T extends "configurationB" ? Whatever<number> :
  never

const createThing = <T extends Options>(type: T): TypeFromOption<T> => {
  switch (type) {
    case "configurationA":
      return a
    case "configurationB":
      return b
  }
}

Expected behavior:

I would expect that typescript should be able to infer that the return type of each case in the switch statement is consistent with what the conditional type returns for the given T

Actual behavior:

Type 'Whatever<string>' is not assignable to type 'TypeFromOption<T>'
Type 'Whatever<number>' is not assignable to type 'TypeFromOption<T>'

Adding as any after return a and return b causes it to work as expected and infer the correct return type for the function.

Playground Link:
http://www.typescriptlang.org/play/#src=const%20a%3A%20TypeFromOption<"configurationA">%20%3D%20%7Bdata%3A%20"test"%7D%0D%0A%0D%0Aconst%20b%3A%20TypeFromOption<"configurationB">%20%3D%20%7Bdata%3A%201%7D%0D%0A%0D%0Ainterface%20Whatever%20%7B%0D%0A%20%20data%3A%20T%0D%0A%7D%0D%0A%0D%0Atype%20Options%20%3D%20"configurationA"%20%7C%20"configurationB"%0D%0A%0D%0Atype%20TypeFromOption<T%20extends%20Options>%20%3D%0D%0A%20%20T%20extends%20"configurationA"%20%3F%20Whatever%20%3A%0D%0A%20%20T%20extends%20"configurationB"%20%3F%20Whatever%20%3A%0D%0A%20%20never%0D%0A%0D%0Aconst%20createThing%20%3D%20<T%20extends%20Options>(type%3A%20T)%3A%20TypeFromOption%20%3D>%20%7B%0D%0A%20%20switch%20(type)%20%7B%0D%0A%20%20%20%20case%20"configurationA"%3A%0D%0A%20%20%20%20%20%20return%20a%0D%0A%20%20%20%20case%20"configurationB"%3A%0D%0A%20%20%20%20%20%20return%20b%0D%0A%20%20%7D%0D%0A%7D

Related Issues:

Activity

  1. RyanCavanaugh commented on Apr 19, 2018

    @RyanCavanaugh
    Member

    Union-constrained generics aren't narrowed, so we don't change the type of type in the switch and don't have any chance to even realize the return statements refer to different cases. I'm not sure there's any concrete next step we could do to fix this - in general we cannot reason very strongly about a type parameter because we can't reason about a domain that doesn't exist yet, though literal-union-constrained generics might be a special case. But there's no mechanism in place right now to unify the flow control behavior with the conditional types - without more scenarios I think this is pretty far out of scope.

    #23132 might be related

  2. leighman commented on Apr 20, 2018

    @leighman
    Author

    Yeh, thought typescript might be able to do more because it was a union of literals.
    Thanks for the info.

  3. typescript-bot commented on May 4, 2018

    @typescript-bot
    Contributor

    Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

  4. locked and limited conversation to collaborators on Jul 31, 2018
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

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions