英文:
How to wrap function and extend custom arguments with right type
问题
I've translated the code part for you:
const func = (a: string) => {
console.log(a);
}
type Options = {
force?: boolean
};
const wrapFunc = <A extends any[], R>(fn: (...args: A) => R) => {
const wrappedFunc = (...args: A & [options?: Options]) => {
const options: Options = 'force' in args[args.length - 1] ? args.pop() : {};
fn(...(args as A))
}
return wrappedFunc;
}
const newFunc = wrapFunc(func);
newFunc('a', {force: true})
// Argument of type '["a", { force: true; }]' is not assignable to parameter of type '[a: string] & [options?: Options | undefined]'.
// Type '["a", { force: true; }]' is not assignable to type '[a: string]'.
// Source has 2 element(s) but target allows only 1.(2345)
Please note that code translations may vary depending on the context and purpose.
英文:
I want wrap callback function and extend custom arguments, And i get error type alert
const func = (a: string) => {
console.log(a);
}
type Options = {
force?: boolean
};
const wrapFunc = <A extends any[], R>(fn: (...args: A) => R) => {
const wrappedFunc = (...args: A & [options?: Options]) => {
const options: Options = 'force' in args[args.length - 1] ? args.pop() : {};
fn(...(args as A))
}
return wrappedFunc;
}
const newFunc = wrapFunc(func);
newFunc('a', {force: true})
// Argument of type '["a", { force: true; }]' is not assignable to parameter of type '[a: string] & // [options?: Options | undefined]'.
// Type '["a", { force: true; }]' is not assignable to type '[a: string]'.
// Source has 2 element(s) but target allows only 1.(2345)
here is reproduced TypeScript playground
Could somebody help me make is right. Thanks!
答案1
得分: 0
The &
operator is not what you should use. number[] & {prop: string}
will expect an array with a prop
property typed as a string
, not another element. To push an element to a generic array parameter, you can do as follows: <A extends unknown[]>(args: [...A, Options]
This one isn't suitable for us since we want to have optional options, and it can be achieved by telling the compiler that we expect A
or A
with options:
args: [...A, Options] | A
Implementation:
const wrapFunc = <A extends any[], R>(fn: (...args: A) => R) => {
const wrappedFunc = (...args: [...A, Options] | A) => {
const options: Options = 'force' in args[args.length - 1] ? args.pop() : {};
fn(...(args.slice(-1) as A));
};
return wrappedFunc;
};
// const newFunc: (...args: [a: string] | [string, Options]) => void
const newFunc = wrapFunc(func);
This works as expected; however, the label of a
is removed in the hinting when you also accept Options
. To fix it, we should use labeled tuples as follows:
const wrappedFunc = (...args: [...mainArgs: A, options: Options] | A) => {}
This way hinting will be better:
// const newFunc: (...args: [a: string] | [a: string, options: Options]) => void
const newFunc = wrapFunc(func);
Note: You can also consider using the following approach, however, it may throw some Typescript errors depending on your tsconfig:
const wrappedFunc = (...args: [...mainArgs: A, options?: Options]) => {}
// const newFunc: (a: string, options?: Options) => voi
const newFunc = wrapFunc(func);
英文:
The &
operator is not what you should use. number[] & {prop: string}
will expect an array with a prop
property typed as a string
, not another element. To push an element to a generic array parameter, you can do as follows:
<A extends unknown[]>(args: [...A, Options]
This one isn't suitable for us since we want to have optional options, and it can be achieved by telling the compiler that we expect A
or A
with options:
args: [...A, Options] | A
Implementation:
const wrapFunc = <A extends any[], R>(fn: (...args: A) => R) => {
const wrappedFunc = (...args: [...A, Options] | A) => {
const options: Options = 'force' in args[args.length - 1] ? args.pop() : {};
fn(...(args.slice(-1) as A));
};
return wrappedFunc;
};
// const newFunc: (...args: [a: string] | [string, Options]) => void
const newFunc = wrapFunc(func);
This works as expected; however, the label of a
is removed in the hinting when you also accept Options
. To fix it, we should use labeled tuples as follows:
const wrappedFunc = (...args: [...mainArgs: A, options: Options] | A) => {}
This way hinting will be better:
// const newFunc: (...args: [a: string] | [a: string, options: Options]) => void
const newFunc = wrapFunc(func);
Note: You can also consider using the following approach, however, it may throw some Typescript errors depending on your tsconfig:
const wrappedFunc = (...args: [...mainArgs: A, options?: Options]) => {}
// const newFunc: (a: string, options?: Options) => voi
const newFunc = wrapFunc(func);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论