-
Notifications
You must be signed in to change notification settings - Fork 12.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compiler incorrectly reports parameter/call target signature mismatch when using the spread operator #4130
Comments
And the same is for when function foo(x: number, y: number, z: number) { }
function bar(...args) {
foo(...args); // Supplied parameters do not match any signature of call target.
} |
this is currently by design. but we should reconsider it. |
@smashdevcode, @tjoskar, I'm looking for some real-world uses of this feature. Specifically, do you expect to spread arrays or tuples (or both maybe)? Here are couple of toy examples: //// arrays ////
var a1: number[] = [1,2];
var a2: number[] = [1,2,3];
var a3: number[] = [];
function twoNumbersOrSo(n?: number, m?: number) {
return (n || -1) * (m || -1);
}
function howManyNumbersLessOne(n?: number, ...ns: number[]) {
return ns.length;
}
//// tuples ////
var t1: [number, string] = [1, "foo"];
var t2: [number, string, string] = [1, "foo", "bar"];
function veryTraditional(n: number, s: string) {
for (let i = 0; i < n; i++) {
console.log(s);
}
}
function moreInteresting(n: number, s: string, ...rest: string[]) {
veryTraditional(n, s);
console.log(rest);
} Now any of Notice that with arrays:
With tuples:
|
Hi @sandersn, Sorry for late response. I totally missed your reply. Example with function foo(...args) {
console.log(...args);
}
var bar = new Set().add(1).add(2);
foo(...bar); // 1, 2 |
Yeah, it's a separate issue. Typescript already supports arrays as the type for rest parameters, which is the thing that would need to be made generic. We're just discussing where spread args could be used. Do you want to pass your homogenous arrays/sets to functions with rest-parameters or ones with a fixed number of arguments? I'd like more detail on the thing you would be calling. |
First of all, I have playing around with the spread operator this morning and most of my use cases works fine in the latest version of typescript However, However, I think it would be nice if the parameters don't need to be optional and that the compiler function fun1(x: number, y: number, z: number) {
return x+y+z;
}
let arr1 = [1, 2, 3];
let arr2 = [1, 2];
fun1(...arr1);
fun1(...arr2); // OK since `arr2` is number[]
fun1(1, 2); // Should cause an error Is that possible? The following code works in the current version of typescript, which it didn't when this issue was addressed. function fun1(...num) {
return Math.max(...num);
}
function fun2(a1, ...num) {
return Math.max(...num);
}
function fun3(a1, ...num) {
return fun1(...num);
}
let arr = [1, 2, 3];
if (Math.random() < .5) {
arr.push(1);
}
fun1(...arr);
fun2('first param', ...arr);
fun3('first param', ...arr); Maybe a more realistic example (that also works nowadays): const doSomeWork = ({title, genre, runtime}) => { console.log(title, genre, runtime); };
function fun1(...num) {
num.forEach(doSomeWork);
}
const data = [{
title: 'title',
genre: ['action', 'drama'],
runtime: 100
}];
fun1(...data); |
👍 Having the same issue, with the specific use case of the let dateNumberArray: Array<number> = [2015,11,11];
let myNewDate = new Date(...dateNumberArray); |
For us we use spreads to allow users to configure argv requirements in a base app without the need to build their own helpers. For example:
get appArgs() : { yargv: Array<Array<any>>, chdir: Array<boolean | string> } {
return require(
"../args.json"
)
}
argv() : Promise<{}> {
return new Promise((resolve) => {
this.appArgs.yargv.forEach(v => yargs.option(...v))
return resolve(yargs.usage("$0 [args]").help("h").
alias("h", "help").argv)
})
} |
A real world example using the combineLatest function of https://github.com/ReactiveX/rxjs where I want to preserve the
Currently I have to do
|
FWIW, another real world example is trying to deep merge an array of objects using merge from lodash: import { merge } from 'lodash';
...
return merge(...arrayOfObjects); |
Here's another real world use case; we're trying to refactor code that looks like this: return Observable
.forkJoin(a, b)
.map(([current, past]) => this.mergeData(current, past)); Into the slightly more elegant: return Observable
.forkJoin(a, b)
.map(data => this.mergeData(...data)); But using the spread operator triggers the signature mismatch error. |
Another real world example, in which correct handling of spread operator in function call will help a lot: The generated function looks like following:
I want to call it with syntax
because there are more functions with exactly the same parameters (because they are generated from the same parameters class defined in C# backend). Now I have to copy body of property tableIdentification n-times into each usage |
@smashdevcode For me solution was to add @ts-ignore
example here: https://stackblitz.com/edit/typescript-ecymei?embed=1&file=index.ts |
@darekf77, or if you say that function foo(x: number, y: number, z: number) { }
const args: [number, number, number] = [0, 1, 2];
foo(...args); |
This works for me when I compile typescript in the command line, but not when Visual Studio Code validates the typescript while I'm typing. I'm not sure what the disconnect is here. |
I see it's been over a year since jayphelps mentioned that this would be fixed in an upcoming release, but this issue still occurs. Is there any update on this? I know I could use @ts-ignore however this removes ALL typescript messages for the function so isn't really an appropriate solution. |
@TidyIQ as mentioned by tjoskar, typecast your spread array as a tuple. |
The array isn't fixed-length so that won't work. |
A typecast will work as far as the compiler is concerned, even if it is innacurate. I agree it's not the best solution. |
(This question should probably be moved to stack overflow (or similar)) @TidyIQ, if the array doesn't have a fix length, the compiler can not tell if the array is suitable or not. function foo(x: number, y: number, z: number) { }
const args = arrayOfSomeLength;
foo(...args); // Error: The compiler do not know if there is 3 or 2 or 1 or 50 elements in the array. So if the array is of dynamic length the arguments should be that as well: function foo(...args: number[]) { }
const args = arrayOfSomeLength;
foo(...args); |
Unfortunately that won't work either as some of my args are fixed length. Perhaps if I just post the code you might see the issue.
|
@TidyIQ, I'm not sure I follow. What happens if Should not this work: const createState = (...args: string[]) => (object: IF_Object = {}) => {
const [key, value, ...rest] = args;
if (rest.length === 0) {
setKV(key, value)(object)
} else {
setKV(key, createState(value, ...rest)(object[key]))(object);
}
} |
Cast to spread value as the const add = (a: number, b: number) => a + b
const values = {
a: 1,
b: 2,
}
type AddParams = Parameters<typeof add>
add(...(values) as AddParams) |
@mateja176 This also seems to work and might better suit some use cases. add(...(values as [number,number])) or add(...(values as [any,any])) |
I use a helper type for this to handle arbitrary arrays without having to type them explicitly: type NonEmptyArray<T extends any[]> = T extends (infer U)[]
? [U, ...U[]]
: never It can be used like this: add(...values as NonEmptyArray<typeof values>) Detailed explanation for beginnersThe following dissection of the
Now if we do this... const values = [1,2,3]
add(...values as NonEmptyArray<typeof values>) ...the following will happen:
|
@tjoskar change your code to
(playground) Surprisingly, if you were to change the last line to |
I feel like this still isn't working. Here is my example
It shouldn't really matter what is the type of |
Here is a reduced form of @Haaxor1689's example: |
I still can't get it working this is my temporary workaround
|
I feel like this is still a problem (just encountered this). Is there another open issue for this, or would it be relevant to re-open this one? |
@ahejlsberg this issue either persists or there is a regression in the latest TS version. |
The compiler incorrectly reports a parameter/call target signature mismatch when using the spread operator. Pasting this code into the TypeScript Playground:
produces this error:
The text was updated successfully, but these errors were encountered: