Typescript: Allow readonly properties to be overridden

Created on 15 Oct 2019  ·  3Comments  ·  Source: microsoft/TypeScript

Search Terms

override readonly

Suggestion

I have many interfaces that have readonly properties. This is because in standard usage, those properties are indeed intended to be treated as readonly. However, when setting them up I want to be able to set those properties with some sort of override command.

Right now, I either just run with an 'any' and cast it after the fact, or just disable type checking of that line altogether. Both methods come with their own disadvantages.

This has been a sticking point in my codebase for years now, and I think this is a wise addition to the language. It keeps the language succinct and means I don't have to do strange workarounds.

Examples

The following example is NOT allowed. I think having some sort of keyword like force could help here.

interface Example {
    readonly a: number,
    readonly b: number,
    readonly someDerivativeProperty: string
}

const row: Example = await getOneRowFromDatabase();
// example row:
// { a: 3, b: 6 }

// complete the object.
// THE BELOW IS NOT ALLOWED AND THERE IS NO WAY TO OVERRIDE IT
row.someDerivativeProperty = (row.a + row.b > 9 ? 'something' : 'something else');

Checklist

My suggestion meets these guidelines:

  • [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [x] This wouldn't change the runtime behavior of existing JavaScript code
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • [x] This feature would agree with the rest of TypeScript's Design Goals.

All 3 comments

Just create a matching type that does allow mutation:

type Mutable<T> = { -readonly [P in keyof T]: T[P] }

const row: Mutable<Example> = await getOneRowFromDatabase();
row.someDerivativeProperty = (row.a + row.b > 9 ? 'something' : 'something else');
const done: Example = row;

Huh... nice.

That's some black magic though. I wonder if the TS team is happy with this being a solution

That is the intended solution, it's why the possibility to remove the readonly modifier as part of mapped types was added (same with making it non-optional, or vice-versa). And definitely to be preferred over another keyword like forced.

Was this page helpful?
0 / 5 - 0 ratings