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

Function return type is not implied conditionally based on type of parameter #30262

Closed
joshuafairchild1 opened this issue Mar 7, 2019 · 4 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@joshuafairchild1
Copy link

TypeScript Version: 2.9.2

Search Terms:
typescript return type based on parameter
Code

type StringOrNull<B extends Boolean> = B extends true ? string : (string | null)
type StringNotNull = StringOrNull<true>

function foo<B extends boolean>(returnString: B): StringOrNull<B> {
  if (returnString) {
    return '' as StringNotNull // type error: "Type 'string' is not assignable to type 'StringOrNull<B>'"
  } else {
    return null
  }
}

Expected behavior:

Typecast should be valid, with the return type of foo being:

  • string when returnString is passed as true
  • string | null when returnString is passed as false

Actual behavior:
Cast cannot succeed, and return type is not dynamic based on the boolean passed to foo

Playground Link:
https://www.typescriptlang.org/play/#src=type%20StringOrNull%3CB%20extends%20Boolean%3E%20%3D%20B%20extends%20true%20%3F%20string%20%3A%20(string%20%7C%20null)%0D%0Atype%20StringNotNull%20%3D%20StringOrNull%3Ctrue%3E%0D%0A%0D%0Afunction%20foo%3CB%20extends%20boolean%3E(throwError%3A%20B)%3A%20StringOrNull%3CB%3E%20%7B%0D%0A%20%20if%20(throwError)%20%7B%0D%0A%20%20%20%20throw%20Error()%0D%0A%20%20%7D%0D%0A%20%20return%20''%20as%20StringNotNull%0D%0A%7D

Related Issues:

@weswigham
Copy link
Member

StringNotNull expressly passes true to your helper which expressly resolves to just string (it has no generics left so is no longer actually a conditional; it's already "executed"). You should probably just cast to StringOrNull<typeof returnString> to retain the dependence on B instead.

@joshuafairchild1
Copy link
Author

StringNotNull expressly passes true to your helper which expressly resolves to just string (it has no generics left so is no longer actually a conditional; it's already "executed"). You should probably just cast to StringOrNull<typeof returnString> to retain the dependence on B instead.

Casting to StringOrNull<typeof returnString> will still result in the same type error that 'string' is not assignable to type 'StringOrNull<B>'. I was, however, able to make the cast succeed by casting to StringOrNull<B>, though that route doesn't fix the root issue that the return type of foo will then always be string, independent of the passed boolean.

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Mar 7, 2019
@poseidonCore
Copy link

The problem is that the conditional type does not collapse to a basic type.

This is a reduced example.

TS Playground

@jack-williams
Copy link
Collaborator

This is tracked by #26933.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

5 participants