- Sound mode S-05, pre-alpha
- Design record 0007, Accepted
TSR0501
'{0}' is not assignable to '{1}': mutable '{2}' is invariant in sound mode, so writes through '{1}' could break '{0}'. Use '{3}' if it is only read.
A mutable array, tuple, Map or Set is used as one with a wider element type, so writes could break it. Use the readonly type if it is only read.
Rule S-05: Mutable built-in containers are invariant (level: sound). Reported by ts-r-check and ts-r-lsp in files that opt in to sound mode. See Sound mode.
What it means
In sound files, T[], Array<T>, mutable tuples, Map, Set, WeakMap and WeakSet are invariant: Dog[] is not assignable to Animal[], because code holding the Animal[] could push a Cat into it. The readonly forms (readonly T[], ReadonlyMap, ReadonlySet, Iterable<T>) stay covariant. It's reported where tsc reports assignability errors; {3} names the readonly form.
Example
// string[] to (string | number)[]: a number could be pushed into the string array.
const strings: string[] = ["a"];
const mixed: (string | number)[] = strings; // @expect TSR0501
export const n: number = mixed.length;
How to fix
- If the target is only read, make it readonly:
readonly Animal[],ReadonlyMap<string, Animal>. - Make function parameters that never write
readonly(the planned quick fix does this). - Copy when ownership moves:
[...dogs],new Map(dogMap).
Sound mode is defined in design record 0007 (accepted 2026-10-15).