question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItΒ collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot infer generic argument type from passed callback

See original GitHub issue

TypeScript Version: 3.4.0-dev.201xxxxx

Search Terms:

infer, parameter, argument, callback, function

Code

function inferArguments<T>(callback: ((t: T) => void)) {
  return callback;
}

function noop(){}

const explicit = inferArguments(({a = noop}: {a: Function}) => {});
explicit({a: noop}); // OK!
explicit({a: false}); // Expected error - Got one!

const implicit = inferArguments(({a = noop}) => {});
implicit({a: noop}); // OK!
implicit({a: false}); // Expected error - No Error!

Expected behavior: Both function calls with ({a: false}) should cause a type error

Actual behavior: Only the function call with the explicit typing causes a type error

Playground Link

Related Issues: #30975 Looks similar but seems different since there should be a clear way for inference to work in this case

Note that Parameters is correctly able to extract the correct types for such a construct as seen in this bit of code:

function noop() { }
function callback({ a = noop }) { }
let args: Parameters<typeof callback>;
args[0].a as Function

This appears to be an error with inline callback functions used in this fashion

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:7
  • Comments:14 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
theonlypwnercommented, Sep 21, 2020

A common issue is having to manually specify a type for the Promise constructor. (tested in Visual Studio Code with TypeScript 3.7.2)

const p = new Promise((resolve) => resolve(1))

p is of type Promise<unknown>, so in order to use it later, one has to specify the type explicitly to have p be of type Promise<number>:

const p = new Promise<number>((resolve) => resolve(1))

@pradyuman I’ve also run into the same issue with making my own wrapper for gRPC calls. I found that it is due to having multiple overloads for call (the auto-generated TypeScript declarations have multiple overloads for generated methods in the client), which prevents inference from working.

Here’s a reproducible example (tested in Visual Studio Code with TypeScript 3.7.2), using number instead of gRPC request/response protobuf types:

function f<T, U> (
  call: (
    request: U,
    innerCallback: (error: Error | null, value?: T) => void
  ) => void,
  request: U): Promise<T> {
  return new Promise((resolve, reject) => call(request, (error, response) => {
    if (error) {
      reject(error)
    } else {
      resolve(response)
    }
  }))
}

declare function p (request: number, call: (error: null, a: number) => void)
// declare function p (request: number, a2: boolean, call: (error: null, a: number) => void)

async function g () {
  const v = await f(p, 1)
  // the type of v is inferred as number
  // but if the other declaration above is uncommented, it is inferred as unknown
}

My workaround is to specify the type explicitly (const v: number = await f(p, 1)), which still catches type errors (like const v: boolean = await f(p, 1))

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why TypeScript cannot infer callback argument type based on ...
The problem is that TypeScript does not use control flow analysis to narrow or constrain generic type parameters.
Read more >
Understanding infer in TypeScript - LogRocket Blog
The infer keyword and conditional typing in TypeScript allow us to take a type and isolate any piece of it for later use....
Read more >
Typescript: Type Inference on function arguments (huge update)
T generic parameter was infered to 42 which is perfectly fine. It was infered as a literal 42 instead of just number ....
Read more >
typing β€” Support for type hints β€” Python 3.11.1 documentation
The Python runtime does not enforce function and variable type annotations. ... objects kept in containers cannot be statically inferred in a generic...
Read more >
Documentation - More on Functions - TypeScript
Just like with function declarations, if a parameter type isn't specified, ... TypeScript can usually infer the intended type arguments in a generic...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found