如何在打字稿中分配具有不同/附加参数的函数类型

问题描述 投票:0回答:1
// 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

evaluate_two(tesstobj, 'one', callback2) // ????

在上面的代码片段中,我需要能够将

callback1
/
callback2
/
callback3
传递给
evaluate
的回调参数。我尝试在
evaluate_two
中实现这一目标,但没有成功。

错误信息

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'.

游乐场链接

注意:我知道这可以通过 union 来实现,但它不是动态的,我不喜欢这一点。

javascript typescript
1个回答
0
投票

您可以传递回调,更新代码

// 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' }

const evaluate_two = <
    O extends Obj,
    F1 extends () => ReturnType<F1>
>(obj: O, prop: keyof O, vfunc: F1) => {
    if (typeof prop !== 'string') throw new Error('error')
    return vfunc();
}

evaluate_two(tesstobj, 'one', () => {
    callback1('one', tesstobj['one']);
})

evaluate_two(tesstobj, 'one', () => {
    const temp_min = -10;
    const temp_max = 10;
    callback2('one', tesstobj['one'], temp_min, temp_max);
})

evaluate_two(tesstobj, 'one', () => {
    const something = 100;
    callback3('one', tesstobj['one'], something);
})

编辑(根据@bogdanoff的评论更新答案):

// 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' }

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: any[]) => ReturnType<F> // <--
>(obj: O, prop: keyof O, vfunc: F , ...args: any[]) => {
    if (typeof prop !== 'string') throw new Error('error')
    return vfunc(prop, obj[prop], ...args)
}

evaluate_two(tesstobj, 'one', callback1) 
evaluate_two(tesstobj, 'one', callback2) 
evaluate_two(tesstobj, 'one', callback3) 

只需将参数类型从known[]更改为any[]。希望这有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.