Skip to content

literal function with structure spread can't be rightly inferred in function's generic type slot #28816

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

Closed
zheeeng opened this issue Dec 3, 2018 · 2 comments · Fixed by #36476
Assignees
Labels
Bug A bug in TypeScript Domain: Contextual Types The issue relates to contextual types Fix Available A PR has been opened for this issue

Comments

@zheeeng
Copy link

zheeeng commented Dec 3, 2018

TypeScript Version: 3.2.1

Search Terms:

strucutre spread + generic

Code

function id<T>(input: T): T { return input }

function getFoo ({ foo = 42 }) {
  return foo
}

const newGetFoo = id(getFoo)
const newGetFoo2 = id(function getFoo ({ foo = 42 }) {
  return foo
})

Expected behavior:

newGetFoo and newGetFoo2 should have the same signature

Actual behavior:

newGetFoo is:

({ foo }: {
    foo?: number | undefined;
}) => number

but newGetFoo2 is

 ({ foo }: any) => number

Playground Link:
http://www.typescriptlang.org/play/index.html#src=function%20id%3CT%3E(input%3A%20T)%3A%20T%20%7B%20return%20input%20%7D%0A%0Afunction%20getFoo%20(%7B%20foo%20%3D%2042%20%7D)%20%7B%0A%20%20return%20foo%0A%7D%0A%0Aconst%20newGetFoo%20%3D%20id(getFoo)%0Aconst%20newGetFoo2%20%3D%20id(function%20getFoo%20(%7B%20foo%20%3D%2042%20%7D)%20%7B%0A%20%20return%20foo%0A%7D)%0A

Related Issues:

@weswigham weswigham added Bug A bug in TypeScript Domain: Contextual Types The issue relates to contextual types labels Dec 4, 2018
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 3.3 milestone Dec 8, 2018
@ahejlsberg
Copy link
Member

ahejlsberg commented Jan 25, 2019

Our intended design is to determine the type of a parameter from one of the following, in order of preference:

  1. Explicit type annotation
  2. Contextual parameter type
  3. Initializer type
  4. Type implied by binding pattern

See original discussion and rationale here.

For the getFoo function we end up using the type implied by the binding pattern (i.e. ({ foo }: { foo?: number }) => number) because there is no type annotation, contextual type, or initializer type. This is working as intended.

However, for the function expression passed as an argument to id we do have a contextual type, namely T. Since T has no constraint we should end up inferring an implicit any type for the parameter, but this isn't quite working correctly.

So, the bug here is that newGetFoo2 should have type ({ foo }: any) => any and in -noImplicitAny mode we should report an implicit any error on foo.

EDIT: In retrospect, I now agree newGetFoo2 should have the same type as getFoo and newGetFoo. #36476 has the fix.

@ahejlsberg
Copy link
Member

Fix in #36476 now produces the result expected in the original post.

@ahejlsberg ahejlsberg added Fix Available A PR has been opened for this issue and removed Fixed A PR has been merged for this issue labels Jan 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: Contextual Types The issue relates to contextual types Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants