Paul Deschamps
Paul Deschamps

Reputation: 63

Typescript typing for a Multi Dimensional Array

I am creating a matrix / 2d array of booleans and I want to infer a type that isn't simply "ANY" for dategrid.

let yearRange = [2000,2001,2002,2003,2004];
let monthRange = [0,1,2,3,4,5,6,7,8,9,10,11];
let dateGrid = any;

yearRange.forEach((year) => {
    monthRange.forEach((month) => {
        dateGrid[year][month] = true;
    });
});

How does one create an interface / type for dategrid that:

Infers the structure: e.g. dateGrid[yearIndex][possibleMonthValues]:boolean And restricts the months index to only the applicable months.

dateGrid[2000][0] = true
dateGrid[2000][1] = true
dateGrid[2000][2] = true
dateGrid[2000][3] = true
dateGrid[2000][4] = true
dateGrid[2000][5] = true
dateGrid[2000][6] = true
dateGrid[2000][7] = true
dateGrid[2000][8] = true
dateGrid[2000][9] = true
dateGrid[2000][10] = true
dateGrid[2000][11] = true
dateGrid[2001][0] = true

... and so on ...

Upvotes: 3

Views: 451

Answers (1)

Maciej Sikora
Maciej Sikora

Reputation: 20132

Record based solution

To be totally strict we can infer the proper narrowed types from variables you have given by using const keyword. As I assume years are only example, so the sweet spot would be only restrict months, and leave years as number:

// use const in order to get proper types
let yearRange = [2000,2001,2002,2003,2004];
let monthRange = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] as const;
type Month = typeof monthRange[number];

let dateGrid: Record <number,Record<Month, boolean>>;

Record<Month, boolean> will be good idea if we restrict to have all months from 0 to 11. If we allow on only part of months in the year we can create non-exlusive Record:

let dateGrid: Record<number, Partial<Record<Month, boolean>>> = {
  [2000]: {
    "0" : false 
  }
} // valid as not all fields needs to be provided
const a = dateGrid[2000][4] // boolean | undefined

// in contrary exclusive type
let dateGridExclusive: Record<number, Record<Month, boolean>> = {
  [2000]: {
    "0" : false 
  }
} // error all months need to be provided
const b = dateGrid[2000][4] // boolean

Pay attention that I have used Partial utility type in order to loose the constraint and allow on part of months to be provided.


Array based solution

If we want to use this as array we can perform another array type consider:

type Months = [
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
  boolean,
]

let dateGrid: Months[] // array of 12 element tuples

The minus of using array at year level is that when we set start point of such from 2000, we have 1999 undefined values.

Upvotes: 1

Related Questions