14
votes

My Code:

const WEEKDAYS_SHORT: string[] = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam']

the error message comes from TypeScript (3.0) compiler:

TS2322: Type 'string[]' is not assignable to type '[string, string, string, string, string, string, string]'. Property '0' is missing in type 'string[]'.

enter image description here

if I change the string[] to ReadonlyArray<string>, then the error message becomes:

TS2322: Type 'ReadonlyArray' is not assignable to type '[string, string, string, string, string, string, string]'. Property '0' is missing in type 'ReadonlyArray'.

my tsconfig.json:

{
  "compilerOptions": {
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": ["es6", "dom"],
    "module": "es6",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5",
    "jsx": "react",
    "strict": true
  },
  "exclude": [
    "**/*.spec.ts",
    "node_modules",
    "vendor",
    "public"
  ],
  "compileOnSave": false
}

how can I define a readonly array in TypeScript?

4
Can't reproduce your error, even with strict: true. typescriptlang.org/play/… - Titian Cernicova-Dragomir
hey @TitianCernicova-Dragomir I added the tsconfig.json - Spark.Bao

4 Answers

0
votes

As you point out the issue is cause because you try to assign the string array (string[]) to a 7-string-tuple. While your solution to use any will work it's not generally advisable to use any. Spelling out the supple is also not ideal since it's soo long.

What we can do is create a helper function to create a tuple type. This function is reusable for anywhere you need tuple:

function tupleArray<T extends any[]>(...v: T) {
    return v;
}
const WEEKDAYS_SHORT_INFFERED =  tupleArray('Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam')  // INFFERED AS [string, string, string, string, string, string, string]
const WEEKDAYS_SHORT: [string, string, string, string, string, string, string] = WEEKDAYS_SHORT_INFFERED
30
votes

You may add as const to your declaration;

const readonlyArray = [1, 2, 3] as const;

Furthermore the type typeof readonlyArray[number] would be 1 | 2 | 3

1
votes

After debugging, I found it is not TypeScript compiler problem, it is because I used a third-party component call DayPicker:

          <DayPicker
            onDayClick={this.handleDayClick}
            selectedDays={posts.day}
            months={MONTHS}
            weekdaysShort={WEEKDAYS_SHORT}
            firstDayOfWeek={1}/>

the type of the prop weekdaysShort is not string[], but [string, string, string, string, string, string, string]

weekdaysShort?: [string, string, string, string, string, string, string];

so TS compile says string[] doesn't match [string, string, string, string, string, string, string].

finally, I just changed the type from string[] to any to avoid this anoy error message, of course, we can change to [string, string, string, string, string, string, string] as well (too long).

-1
votes

I did not reproduce the issue on the TypeScript playground.

But, what about using the inferred type, regardless of what it is (string array string[] or 7-string tuple [string, string, string, string, string, string, string])?

const WEEKDAYS_SHORT = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'];
const sunday = 0;
const dayShortName = WEEKDAYS_SHORT[sunday]; // => 'Dim'

Or an enum?

enum WEEKDAYS_SHORT { 'Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam' }
const sunday = 0;
const dayShortName = WEEKDAYS_SHORT[sunday]; // => 'Dim'

IMO, both option above are better than specifying the type any in this case.