Skip to content

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

Closed

Description

@Pajn

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.

Activity

  1. jcalz commented on Jan 18, 2018

    @jcalz
    Contributor

    Related to #11152, maybe?

  2. RyanCavanaugh commented on Jan 18, 2018

    @RyanCavanaugh
    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.

  3. mhegazy commented on Jan 19, 2018

    @mhegazy
    Contributor

    I believe this is just a duplicate of #11152.

  4. Pajn commented on Jan 19, 2018

    @Pajn
    Author

    Seems to be a duplicate of 11152. Joe Calzaretta (@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.

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

  5. jcalz commented on Jan 19, 2018

    @jcalz
    Contributor

    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.

  6. locked and limited conversation to collaborators on Jul 3, 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

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions