Difference between Readonly<[]> and ReadOnlyArray<>

From a performance point of view there should not be any difference between the two, as at runtime types are erase and the same javascript will run regardless

There is a fundamental difference between the two type at compile time:

Readonly<T> - Is a type that has the same shape as T but all the properties are read-only. In your case the T is the tuple type [string, number], so it will have all the properties of array as well as the indexes 0 and 1. So we can call the push method, but we can't reassign the concat method.

let readonlyArray: Readonly<[string, number]> = ["test", 1, 1];
readonlyArray.concat = ()=> {} // Not valid, concat is readonly 
readonlyArray.push(1); // This is valid 
readonlyArray[1] =  ""; // Invalid we cannot change a property by indexing 
readonlyArray[3] =  ""; // Valid as it was not in the original tuple type 

Edit: Since 3.4, typescript has changed the behavior of mapped types on array and tuples, so Readonly<[string, number]> is now equivalent to a readonly tuple readonly [string, number], so the errors are a bit different:

let readonlyArray: Readonly<[string, number]> = ["test", 1];
readonlyArray.concat = ()=> {} // Not valid, concat is readonly 
readonlyArray.push(1); // This is not invalid, no push method anymore
readonlyArray[1] =  ""; // Invalid we cannot change a property by indexing 
readonlyArray[3] =  ""; // Invalid now tuple length preserved

</Edit>

ReadonlyArray<T> is a true readonly array that does not have any methods that can change the array. In your case any item of the array can be either a string or a number:

let readonlyArray2: ReadonlyArray<string | number> = ["test", 1, 1];
readonlyArray2.concat = ()=> []; // Valid we can set the concat property on the object 
readonlyArray2.push(1) // No push method, invalid
readonlyArray2[1] =  ""; // Invalid it is read only 
readonlyArray2[3] =  ""; // Invalid it is read only 

Readonly

  • The Readonly<T> is not necessarily an array; that expects any type <T>
  • To make the Readonly to store an array of values, the type <T> should be an [T]
  • Does not contain mutable methods

    let readonlyArray: Readonly<string| number> = ["test", 1, 1];    // not assignable
    
    let readonlyArray: Readonly<[string| number]> = ["test", 1, 1]; // assignable
    

ReadonlyArray

  • The ReadonlyArray accepts by default an array
  • Contains mutable methods

    let readonlyArray: ReadonlyArray<string| number> = "test";      // not assignable
    
    let readonlyArray: ReadonlyArray<string| number> = ["test"];   // assignable