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
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With