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

Fails to infer type parameters from where return value is assigned #21275

Closed
Pajn opened this issue Jan 18, 2018 · 5 comments
Closed

Fails to infer type parameters from where return value is assigned #21275

Pajn opened this issue Jan 18, 2018 · 5 comments
Labels
Duplicate An existing issue was already created

Comments

@Pajn
Copy link

Pajn commented Jan 18, 2018

TypeScript Version: 2.7.0-dev.20180117

Search Terms:
generic, return, infer, inference, type parameter

Code

type Path<T, V> = Array<string>

function path<T, A extends keyof T>(key: A): Path<T, T[A]>
function path<T>(path: string|Array<string>): Path<T, any> {
  if (typeof path === 'string') return [path] as Path<T, any>
  else return path as Path<T, any>
}

function field<T, V>(path: Path<T, V>) {
  return {path}
}

type User = {name: string}

// Errors
field<User, string>(path('name'))

// Works
field<User, string>(path<User, 'name'>('name'))

Expected behavior:
path should have all type information it needs by the fully typed field call and therefor build without explicit type arguments.

If I can freely imagine the steps the compiler would take:

  1. The compiler detects that it's not possible to infer Path::T and therefor also Path::A from the arguments
  2. The compiler realizes that the return value is Path<T, T[A]> and is assigned to Path<User, string> and can therefor infer that T = User
  3. As the compiler now knows T it now knows that A is A extends keyof User
  4. It can now infer that A = 'name' from the argument
  5. It now knows that T[A] is User['name'] which is string
  6. Finally, as the return value now is fully resolved as Path<User, string> which is assigned to an argument of type Path<User, string> there should be no build errors

Actual behavior:
Error: Argument of type '"name"' is not assignable to parameter of type 'never'..
Presumably Path::T is inferred to be {} and Path::A naturally then becomes never

Playground Link: https://www.typescriptlang.org/play/#src=type%20Path%3CT%2C%20V%3E%20%3D%20Array%3Cstring%3E%0D%0A%0D%0Afunction%20path%3CT%2C%20A%20extends%20keyof%20T%3E(key%3A%20A)%3A%20Path%3CT%2C%20T%5BA%5D%3E%0D%0Afunction%20path%3CT%3E(path%3A%20string%7CArray%3Cstring%3E)%3A%20Path%3CT%2C%20any%3E%20%7B%0D%0A%20%20if%20(typeof%20path%20%3D%3D%3D%20'string')%20return%20%5Bpath%5D%20as%20Path%3CT%2C%20any%3E%0D%0A%20%20else%20return%20path%20as%20Path%3CT%2C%20any%3E%0D%0A%7D%0D%0A%0D%0Afunction%20field%3CT%2C%20V%3E(%0D%0A%20%20path%3A%20Path%3CT%2C%20V%3E%0D%0A)%20%7B%0D%0A%20%20return%20%7Bpath%7D%0D%0A%7D%0D%0A%0D%0Atype%20User%20%3D%20%7Bid%3A%20string%2C%20name%3A%20string%2C%20birthdate%3F%3A%20Date%7D%0D%0A%0D%0A%2F%2F%20Errors%0D%0Afield%3CUser%2C%20string%3E(path('name'))%0D%0A%0D%0A%2F%2F%20Works%0D%0Afield%3CUser%2C%20string%3E(path%3CUser%2C%20'name'%3E('name'))

Related Issues:
There are many issues related to inference or generics but I can't find any related that I imagines involves the same resolution logic.

@jcalz
Copy link
Contributor

jcalz commented Jan 18, 2018

Related to #11152, maybe?

@RyanCavanaugh
Copy link
Member

There may be more going on here, but the unconsumed type parameters in Path are definitely problematic. Intersecting some optional properties of type T and V fix the issue.

@mhegazy
Copy link
Contributor

mhegazy commented Jan 19, 2018

I believe this is just a duplicate of #11152.

@mhegazy mhegazy added the Duplicate An existing issue was already created label Jan 19, 2018
@Pajn
Copy link
Author

Pajn commented Jan 19, 2018

Seems to be a duplicate of 11152. @jcalz May I ask what searchterm you used to find that? I expected something would be there but no matter what I tried I could not find it.

@RyanCavanaugh That was an initial suspicion of mine, but I did try something like & {__type_tag?: [T, A]} without any difference.

@jcalz
Copy link
Contributor

jcalz commented Jan 19, 2018

I think I just searched for "return" and "inference", which are in your list of terms. My advantage was the vague recollection that I had seen such an issue before.

@Pajn Pajn closed this as completed Jan 22, 2018
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants