DEV Community

JSmith AR
JSmith AR

Posted on

TypeScript Sandbox: Function `head`

This will be a series of articles related with TypeScript, here I will try to explore the features of TS, and some Functional Programming concepts.

Function Head

function head(array) {
  if (array.length === 0) throw new Error("array is empty");
  return array[0];
}

head([1, "hello", {}]);
// out: 1, type: any

the function head returns the first element of the array, if the array is empty head throws an Error. The problem with this vanilla js function is that it doesn't have typing.

Let's fix this situation with TS

function head<T extends any[]>(array: T): Head<T>;

const my_array: [number, string, object] = [1, "hello", {}];
head(my_array);
// out: 1, type: number

Now our function is safer, head take a parameter T restricted to arrays and return the first element of array preserving the type (Head<T>)

NOTE: I define my_array explicitly else TS infer my_array as (number | string | object)[], and that's not good for our purpose.

Type HEAD

Let's see Head

type Head<T extends any[]> = T extends [] ? never : T[0];

Head take a list and then check if T is an empty array and return never, else return the first type of the array T. Remember that never designate a value that never ocurrs, It's perfect when we need to throw exceptions, but it has other uses as well.

If we put everything together

type Head<T extends any[]> = T extends [] ? never : T[0];

function head<T extends any[]>(array: T): Head<T> {
  if (array.length === 0) throw new Error("array is empty");
  return array[0];
}

head(my_array);
// out: 1, type: number

head([] as []);
// throw Error, type: never

type Number = Head<typeof my_array>;
// type: number

and that's all ... :)

Discussion (0)