4

This pattern is throwing the TypeScript error:

Argument of type '(string | number)[]' is not assignable to parameter of type 'string[] | number[]'

function foo(value: string | number) {
  return bar([value]); // <- TypeScript error
}

function bar(valueList: string[] | number[]) {
  ..does something...
}

I understand this is because TypeScript compiler will see this as an array with a mix of strings and numbers.

Is there a type-safe way to accomplish this? I can only think to cast to any[] which feels bad:

function foo(value: string | number) {
  const valueList: any[] = [value];
  return bar(valueList);
}
1
  • Did you notice the difference between string and string[] ? Commented Dec 7, 2018 at 8:04

3 Answers 3

4

One way to do this is declaration merging; define two separate interfaces for your function (see function types), then a single implementation of it:

interface Foo {
    (value: string): void;
}

interface Foo {
    (value: number): void;
}

const foo: Foo = function (value) {
  return bar([value]);
}

This will keep the two types separate, as only one of those interfaces can be called through at any given time.

Sign up to request clarification or add additional context in comments.

3 Comments

Is there a reason, you're not using something like this: function foo(value: string); function foo(value: number); function foo(value: any) { return bar([value]); }
@ChristophLütjen I did not know you could do it like that!
Thx, wasn't sure if it was deprecated or the separate interface has other benefits ;-)
2

This is inspired by jonrsharpe's answer but instead of using a separate interface, it uses function overloading.

Function overloads allow us to specify multiple signatures for a single implementation: https://www.typescriptlang.org/docs/handbook/functions.html#overloads

function foo(value: string);
function foo(value: number);
function foo(value: any) {
    return bar([value]);
}

function bar(valueList: number[] | string[]) {
}

Comments

1

The other answer is good (I've upvoted it), but I would personally go with

return bar([value] as string[] | number[]);

especially, if I am short on time. This does not mean that it's wrong or hackish, you are just hinting to silly (in this case) Typescript a bit.

P.S. As @paleo mentioned, this is not completely type-safe.

3 Comments

Your solution is not really type-safe because you could write: function foo(value: string | boolean) { return bar([value] as string[] | number[]); } (with a boolean value as parameter).
Personally, I avoid overly verbose solutions. I would just use a as any until a next version of TypeScript correctly infers this case. Maybe also opening a ticket on GitHub. But I don't propose this answer for fear of downvotes. ;)
@Paleo agree on everything.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.