Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # 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
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants