// callbacks
const callback1 = (key: string, value: unknown) => {
if (typeof value !== 'number' || Number.isNaN(value)) throw new Error('error ' + key)
return value
}
const callback2 = (key: string, value: unknown, min: number, max: number = Infinity) => {
if (typeof value !== 'number' || Number.isNaN(value)) throw new Error('error ' + key)
if (value < min || value > max) throw new Error('error')
return value
}
const callback3 = (key: string, value: unknown, something: number) => {
if (typeof value !== 'number' || Number.isNaN(value)) throw new Error('error ' + key)
if (value === something) throw new Error('error')
return value
}
type Obj = { [P: string]: unknown }
const tesstobj: Record<string, unknown> = { one: 1, two: 'two' }
// main
const evaluate = <
O extends Obj,
F extends (key: string, val: unknown) => ReturnType<F> // <--
>(obj: O, prop: keyof O, vfunc: F) => {
if (typeof prop !== 'string') throw new Error('error')
return vfunc(prop, obj[prop])
}
const evaluate_two = <
O extends Obj,
F extends (key: string, val: unknown, ...args: unknown[]) => ReturnType<F> // <--
>(obj: O, prop: keyof O, vfunc: F , ...args: unknown[]) => {
if (typeof prop !== 'string') throw new Error('error')
return vfunc(prop, obj[prop], ...args)
}
evaluate(tesstobj, 'one', callback1) // good
evaluate(tesstobj, 'one', callback2) // error as expected
// below expression statements should not fail
evaluate_two(tesstobj, 'one', callback2) // should say missing `min` arg
evaluate_two(tesstobj, 'one', callback2, 1)
evaluate_two(tesstobj, 'one', callback2, 1, 10)
evaluate_two(tesstobj, 'one', callback3, 1) // should say wrong type number instead of string
In above snippet I need to able to pass callback1
/ callback2
/ callback3
to evaluate
‘s callback parameter along with its additional arguments. I tried achieve this in evaluate_two
but it didn’t work.
Error message
Argument of type '(key: string, value: unknown, min: number, max?: number) => number' is not assignable to parameter of type '(key: string, val: unknown, ...args: unknown[]) => number'.
Types of parameters 'min' and 'args' are incompatible.
Type 'unknown' is not assignable to type 'number'.
Note: I know this can be achieved with help of union but its not dynamic, which I don’t like.
Edit: Here is updated playground link now with clarifications in response to jcalz’s comment.
2
Answers
You can pass a callback, updated code
Edit (updated answer as per @bogdanoff’s comment):
just change args types from unknown[] to any[]. Hope this helps.
If you want to make sure that
args
matches the rest of the parameters forF
afterkey: string, val: unknown
, then you’ll want another generic type parameter for the type ofargs
:Now you get the behavior you expect:
Playground link to code