Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infer return value from promise in Typescript

Tags:

typescript

I have a very simple function that takes two arguments - node object and async function that somehow processes given node and returns processed node which can be anything.

I would like to make it generic and infer type from async function. This is my try but TS is complaining and I don't really understand why.

// ensure that callback is of a correct type
type NodeCallback<H> = H extends (node: Node) => Promise<infer R> ? (node: Node) => Promise<R> : never

// retrieve return value
type NodeCallbackReturnValue<H> = H extends (node: Node) => Promise<infer R> ? R : never


const myAsyncFunction = <_, C>(node: Node, cb: NodeCallback<C>) => {
  return cb(node)
}


myAsyncFunction(document, (node: Node) => Promise.resolve(node.nodeType))

Playground available here

like image 630
Joozty Avatar asked Apr 19 '21 07:04

Joozty


2 Answers

Alternative solution without explicit generic

type NodeCallback<T> = (node: Node) => Promise<T>

const myAsyncFunction = <R,>(node: Node, cb: NodeCallback<R>) => {
  return cb(node)
}

const result = myAsyncFunction(
  document,
  (node: Node) => Promise.resolve(node.nodeType)
) // Promise<number>

I don't think we need conditional types in NodeCallback type at all, since TS is able to infer the type

Playground

Here you can find more information about working with callbacks

like image 199
captain-yossarian Avatar answered Sep 28 '22 22:09

captain-yossarian


That's because the implicitly declared generic type is unknown in myAsyncFunction(...), and it can't inferred to other type

You can solve it by following:

// change
type NodeCallback<H> = H extends (node: Node) => Promise<infer R> ? (node: Node) => Promise<R> : never
// into
type NodeCallback<H> = H extends (node: Node) => Promise<infer R> ? H : never

Or

const myAsyncFunction = <C,>(node: Node, cb: NodeCallback<C>) => {
  return cb(node)
}

type T = (node: Node) => Promise<number>
myAsyncFunction<T>(document, (node: Node) => Promise.resolve(node.nodeType))

Playground

like image 28
zixiCat Avatar answered Sep 28 '22 20:09

zixiCat