TypeScript Quirks: Spreading types

The spread operator - amazing. One of my favorite additions to javascript in recent years, and one of the most flexible operators in javascript and typescript alike. Unfortunately though, it does have some limitation currently.

I have a bunch of types that define an array of possible names combinations.

type FirstNames = 'Jake' | 'Sid';
type MiddleNames = 'Sid' | 'Unknown';
type LastNames = 'Smith' | 'Something';

type FullName = [FirstNames, MiddleNames, LastNames];

Now, I can use the FullName type for a function parameter to create a full name out of only the possible names I’ve defined above.

function createFullName (args: FullName) {
  return args.join(' ');
}

Well, that works perfectly. I can only call my function with the first, middle and last names I defined myself.

Hang on a second, what if I were to call the function with apply. That way I can turn an array into a list of arguments. Well, I guess I’d define my function like this:

function createFullName (...args: FullName) {

Oh, no, that doesn’t work because “A rest parameter must be of an array type.”… but it is an array, right? Not exactly (actually a tuple, more on this here).

If we instead use the following:

type FullName = Array<FirstNames | MiddleNames | LastNames>;

function createFullName (...args: FullName) {

Then it doesn’t complain about it not being an array, but it does have a few other serious problems.

  1. Now our array of names can be any length
  2. Our names don’t have to be in the correct order

Not ideal.

So, there’s only really one solution - just define the function parameters as regular function parameters. We know how many there are and exactly what types they’ll be anyway.

function createFullName (firstName: FirstName, middleName: MiddleName, lastName: LastName) {

Yes, in this instance this works perfectly well. Probably a bad example on my part, but my point is that the spread operator in typescript is unfortunately a little limited currently.

Another example is that we cannot define an exact set of items in an array, followed by arbitrary ones. For example if I wanted to have other names in my array after first, middle and last, I cannot use this syntax:

type FullName = [FirstNames, MiddleNames, LastNames, ...string];
//                                     type expected ^

Regardless, the spread operator is still awesome, and typescript is developing rapidly with awesome new features all the time, so maybe we’ll see some improvements very soon.