Skip to content

Function type argument inference indirectly lost with generic function #29900

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
andykais opened this issue Feb 13, 2019 · 3 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@andykais
Copy link

TypeScript Version: 3.4.0-dev.20190213 (and 3.3.3)

Search Terms: generic function currying ArgumentTypes infer

Code

type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any
  ? A
  : never

const safeCurry = <
  F extends (...args: any[]) => any,
  G extends (fResult: ReturnType<F>) => any
>(
  gFn: G,
  fFn: F
) => (...args: ArgumentTypes<F>): ReturnType<G> => gFn(fFn(...args))


// (x:number) => number
const curried = safeCurry(
  (x: string) => parseInt(x),
  (x: number) => x.toString()
)

// (...args: any[]) => any
const curried2 = safeCurry(
  <T>(x: T) => x,
  (x: number) => x
)

Expected behavior:
the curried2 function should at least have the signature (x: number) => any, at best it would infer (x: number) => number

Actual behavior:
The args to the currried2 function are incorrect.

The reason why this is the case is confusing to me. Despite gFn being generic, and therefore harder for the compiler to understand what its ReturnType should be, the weird part is that this affects what fFn's argument type inference is. The type signature gFn should not affect how fFn is inferred.

Playground Link: playground link

Related Issues:

@andykais
Copy link
Author

andykais commented Feb 13, 2019

Found another way to express safeCurry using a third generic type. This correctly discovers the argument type of curried2 now, but the return type is still not inferable. Also, the type T is only inferred to be {} and therefore typechecking safeCurry's parameters no longer works (shown in the curried3 function).

type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any
  ? A
  : never

const safeCurry = <
  T,
  F extends (...args: any[]) => T,
  G extends (fResult: T) => any
>(
  gFn: G,
  fFn: F
) => (...args: ArgumentTypes<F>): ReturnType<G> => gFn(fFn(...args))


// (x:number) => number
const curried = safeCurry(
  (x: string) => parseInt(x),
  (x: number) => x.toString()
)

// (x: number) => {}
const curried2 = safeCurry(
  <T>(x: T) => x,
  (x: number) => x
)

// this should throw an error, though it does not
// (x: number) => string
const curried3 = safeCurry(
  (x: string) => x,
  (x: number) => x
)

playground link

@RyanCavanaugh
Copy link
Member

Tracking at #30134

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Feb 27, 2019
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants