Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript: how to declare array of fixed size for type checking at Compile Time

Update: These checks are meant for compile time, not at runtime. In my example, the failed cases are all caught at compile time, and I'm expecting similar behaviour for the other should-fail cases.

Suppose I'm writing a table-like class where I want all members of the class to be arrays of the same length, something like:

class MyClass {
  tableHead:  string[3]; // expect to be a 3 element array of strings
  tableCells: number[3]; // expect to be a 3 element array of numbers
}

The closest solution I've found so far is:

class MyClass {
  tableHead:  [string, string, string];
  tableCells: [number, number, number];
}

let bar = new MyClass();
bar.tableHead = ['a', 'b', 'c']; // pass
bar.tableHead = ['a', 'b'];      // fail
bar.tableHead = ['a', 'b', 1];   // fail

// BUT these also pass, which are expected to fail at compile time
bar.tableHead = ['a', 'b', 'c', 'd', 'e']; // pass
bar.push('d'); // pass
bar.push('e'); // pass

Any better ideas?

like image 566
benjaminz Avatar asked Feb 24 '17 14:02

benjaminz


People also ask

How do I declare a fixed size array in TypeScript?

To declare a fixed length array in TypeScript, we can use the Array constructor or create a tuple. const arr = new Array<number>(3); const tuple: [number, number, number] = [1, 2, 3]; to create the arr array which is an array of numbers with new Array<number>(3) .

How do you declare an array of types in TypeScript?

Arrays can be declared and initialized separately. let fruits: Array<string>; fruits = ['Apple', 'Orange', 'Banana']; let ids: Array<number>; ids = [23, 34, 100, 124, 44]; An array in TypeScript can contain elements of different data types using a generic array type syntax, as shown below.

Is the size of array is fixed?

The length of an array is established when the array is created. After creation, its length is fixed.

How to declare an array with fixed length in typescript?

Use a tuple to declare an array with fixed length in TypeScript, e.g. const arr: [string, number] = ['a', 1]. Tuple types allow us to express an array with a fixed number of elements whose types are known, but can be different.

How to use array_name in typescript?

let array_name [:datatype] = [val1, val2, valn..] 2. Using a generic array type. TypeScript array can contain elements of different data types, as shown below. let array_name: Array = [val1, val2, valn..]

What is this typescript package for?

This package contains type definitions for arrays of fixed length in Typescript. The size of the arrays is checked at compile time. It could be useful in a variety of cases. For example, checking if the correct number of configuration options are passed to a function.

What is type checking in typescript?

Code written in TypeScript is checked for errors before it is executed, during compile time. In this article, we’re going to show type checking in TypeScript at runtime. First, we’ll run through a quick primer on this widely used JavaScript superset.


2 Answers

Update 2: From version 3.4, what the OP asked for is now fully possible with a succinct syntax (Playground link):

class MyClass {
  tableHead: readonly [string, string, string]
  tableCells: readonly [number, number, number]
}

Update 1: From version 2.7, TypeScript can now distinguish between lists of different sizes.

I don't think it's possible to type-check the length of a tuple. Here's the opinion of TypeScript's author on this subject.

I'd argue that what you're asking for is not necessary. Suppose you define this type

type StringTriplet = [string, string, string]

and define a variable of that type:

const a: StringTriplet = ['a', 'b', 'c']

You can't get more variables out of that triplet e.g.

const [one, two, three, four] = a;

will give an error whereas this doesn't as expected:

const [one, two, three] = a;

The only situation where I think the lack of ability to constrain the length becomes a problem is e.g. when you map over the triplet

const result = a.map(/* some pure function */)

and expect that result have 3 elements when in fact it can have more than 3. However, in this case, you are treating a as a collection instead of a tuple anyway so that's not a correct use case for the tuple syntax.

like image 70
Huy Nguyen Avatar answered Oct 20 '22 15:10

Huy Nguyen


From Typescript: Can I define an n-length tuple type?, programmatically, with dynamic length:

type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & { length: TLength };

type Tuple9<T> = Tuple<T, 9>;
like image 24
cancerbero Avatar answered Oct 20 '22 14:10

cancerbero