Devin Roché

Typescript Tuples

The Problem

Imagine you have some code like the following,

const errorsAndFields = [
 [streetAddressError, this.streetAddressInputRef],
 [cityError, this.cityInputRef],
 [stateError, this.stateInputRef],
 [zipCodeError, this.zipCodeInputRef]
];

Where a[0] is a boolean value and a[1] is a ref to some input.

Now how do you type this if we only want to return a ref?


First Try

const errorsAndFields: Array<Array<boolean | React.RefObject<TextInput>>>

So while this would work it wouldn’t result in the most helpful type. Whenever you want to access a value from our array we need to do something like this,

const errorOfField = errorsAndFields.find(i => i[0] === true);

if (typeof errorOfField[1] === 'boolean') {
 // what the heck this is always gonna be a ref
 return null
}
return errorOfField[1]

This works but isn’t ideal and makes the type of errorsAndFields equal to const errorsAndFields: (boolean | React.RefObject<TextInput>)[][] which isn’t correct.


Ideal approach

So there’s a bug with typing tuples in typescript.

We need to create the following function

const tupleArray = <T extends Array<[any] | any[]>>(...a: T): Array<T[number]> => {
 return a;
};

Then call it like

const errorsAndFields = tupleArray(
 [streetAddressError, this.streetAddressInputRef],
 [cityError, this.cityInputRef],
 [stateError, this.stateInputRef],
 [zipCodeError, this.zipCodeInputRef]
)

Now if we check the type of errorsAndFields we finially have the correct type const errorsAndFields: [boolean, React.RefObject<TextInput>][]

This also allows us to access errorOfField by index without having the manually check if the type is boolean!

const errorOfField = errorsAndFields.find(i => i[0] === true);

return errorOfField[1]

Updated Version

So I’ve come across another way we can type this.

If we declare the type as

type ErrorStateAndFieldRefPair = [boolean, React.RefObject<TextInput>];

and then use it like

const errorsAndFields = ([
 [streetAddressError, this.streetAddressInputRef],
 [cityError, this.cityInputRef],
 [stateError, this.stateInputRef],
 [zipCodeError, this.zipCodeInputRef]
 ] as ErrorStateAndFieldRefPair[])

This final solution is much easier to understand and offers stricter typing!

Now we can successfully type tuples in typescript, read more about this ts issue here


twitter |github