Recently in RxJS Primitives
I encountered a situation where
one of the methods - concat
was initially
designed to take an argument list of strings and in the method used rest (...args
) parameters, mimicking the signature
and passing them to the String.prototype.concat
I’ve created a StackBlitz Project with the code for each step that can be followed along.
I wanted to refactor it to support an array of strings, but found that in the current implementation this is not possible and throws a TypeScript error:
|
|
|
|
Due to how TypeScript treats rest parameters, it expects a list of parameters as a single string which is turned into an array-like arguments .
To get around this, we can use TypeScript <code>function</code> overloading .
How to overload functions with rest parameters
My first attempt at writing this method lead to this code which attempts to keep the type information in all implementations:
|
|
This resulted in an error on the second implementation:
|
|
It appears that TypeScript cannot convert an Array rest type to an arguments
Array-like value, to get around this
we need to use the any
value in the last implementation
:
|
|
So now the TypeScript compiler stops complaining, and we can test it using both supported argument types:
|
|
However, if you look at the output of the result you’ll notice a bug in our Array implementation where a comma
appears in the text - the issue is that now the implementation treats the array as the first argument in a list of
arguments
- and changing the last method to be args:any
would remove our rest parameter destructing.
To solve this, we need to use the any
type again to destructure our arguments and check for the first one being an array,
if it is then we use this as our destructured arguments into the String.prototype.concat
method, but if it’s a string
then we pass all the arguments using destructuring:
|
|
Now the implementation works as intended - our method can accept one or more string arguments, or an array of strings as the first argument - and it’s not possible to mix the two up - if you try add a second array to the arguments, the TypeScript compiler will look for single string arguments.