Growing with the Web

Readonly Typed Arrays in TypeScript

Published
Tags:

A proposal to add support for built-in readonly typed arrays got rejected by the TypeScript team. This post shows how to build your own.

The issue calls out this type as a potential workaround:

export interface ReadonlyUint16Array extends Uint16Array {
  readonly [n: number]: number;
};

The keen observer may notice that this only protects index access from mutation though, typed arrays have several methods for modifying the data as well like set and fill. For example:

const a: ReadonlyUint16Array = new Uint16Array(1);
console.log(a[0]); // 0
a.set([1], 0);
console.log(a[1]); // 1

This is what I came up with to properly protect typed arrays:

export interface ReadonlyUint16Array extends Omit<Uint16Array, 'copyWithin' | 'fill' | 'reverse' | 'set' | 'sort'> {
  readonly [n: number]: number;
}

Which should give the following errors:

const a: ReadonlyUint16Array = new Uint16Array(1);

a.set([1], 0);
// Property 'set' does not exist on type 'ReadonlyUint16Array'

a[0] = 2;
// Index signature in type 'ReadonlyUint16Array' only permits reading.

Here are all the typed arrays for convenient copy and pasting:

export type TypedArrayMutableProperties = 'copyWithin' | 'fill' | 'reverse' | 'set' | 'sort';
export interface ReadonlyUint8ClampedArray extends Omit<Uint8ClampedArray, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyUint8Array extends Omit<Uint8Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyUint16Array extends Omit<Uint16Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyUint32Array extends Omit<Uint32Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyInt8Array extends Omit<Int8Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyInt16Array extends Omit<Int16Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyInt32Array extends Omit<Int32Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyFloat32Array extends Omit<Float32Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyFloat64Array extends Omit<Float64Array, TypedArrayMutableProperties> { readonly [n: number]: number }
export interface ReadonlyBigInt64Array extends Omit<BigInt64Array, TypedArrayMutableProperties> { readonly [n: number]: bigint }
export interface ReadonlyBigUint64Array extends Omit<BigUint64Array, TypedArrayMutableProperties> { readonly [n: number]: bigint }

Like this article?
Subscribe for more!