Home > Enterprise >  Generic array which takes first elements type
Generic array which takes first elements type

Time:10-12

There was this challenge

Implement a generic First that takes an Array T and returns its first element's type.

type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];

type head1 = First<arr1>; // expected to be 'a'
type head2 = First<arr2>; // expected to be 3

But I am confused. Since the tasks says we should return first elements type, shouldn't return in first case be string? and in second number?

What am I missing?

Ps. This is the given solution and it indeed returns "a" instead of string

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

Update:

In below code head1 is inferred as string.

let arr1 = ["a", "b", "c"]; // use let instead of type
type head1 = First<typeof arr1>; 

Why when I used type array1 as in my question, head1 was inferred as "a" and above as "string"?

CodePudding user response:

The key is that arr1 and arr2 aren't array types; they're tuple types. In JavaScript, tuples are simply arrays, but in TypeScript's type system every element of a tuple has its own type.

This is easier to see if you use "actual" types instead of literals, for example:

type arr1 = [string, number, Object];

const arr1Value: arr1 = ["hello", 42, {}];

type head1 = First<arr1>; // string

Note that arr1 is not an array. It's a type of array (or tuple), and arr1Value is an array of that type.

If you don't provide the type of an array literal, it is inferred:

let arr1 = ["a", "b", "c"]; // arr1 is of type string[]

Now, the inferred type of arr1 could have been inferred as ['a', 'b', 'c']; that is, a tuple of those three strings. But that's almost never what you want: for example, it wouldn't let you push more values onto the array. So TypeScript infers that it's a string[] instead. (If you do want to infer a tuple type, add as const at the end.)

CodePudding user response:

Type in TypeScript doesn't necessarily have to be string. It is a valid type, however very general.

You can limit the possible strings to say just 'a', 'b' or 'c' using:

type Abc = 'a' | 'b' | 'c';

If you now create a variable with this type declared, you will get compilation error whenever incorrect value is defined:

const name: Abc = 'John'; // TypeScript will mark this as incorrect

Now, to provide you with the solution, apparently this is enough:

type First<T extends any[]> = T[0];
  • Related