In a TypeScript mapped type such as `{ +readonly [K in keyof T]+?: T[K] }`, what does the `+` prefix mean, and how does that type differ from `{ readonly [K in keyof T]?: T[K] }`?
answer
- one direction is the default
- absence of a sign already means something
- only one of the two signs changes anything
- +readonly is just readonly, spelled loudly
basics
~20 sThe plus prefix means add the modifier, which is already what a bare readonly or ? means, so the two mapped types describe exactly the same type. The plus exists only to make the direction explicit alongside the minus form.
solid answer
~40 sThey are the same type. Inside a mapped type, a modifier written bare already means "add it", so `+readonly` is just a louder spelling of `readonly` and `+?` a louder spelling of `?`. The prefix carries no extra meaning and changes nothing about assignability, inference or emit. It exists for symmetry: once TypeScript let you write `-readonly` and `-?` to strip a modifier, having an explicit `+` made the two directions readable side by side, which helps when a codebase has both a `Readonly`-style and a `Mutable`-style helper next to each other. Most real code omits the `+`; the one place you see it is documentation and helpers written to spell out intent.
code
typescript · 12 linestype Explicit<T> = { +readonly [K in keyof T]+?: T[K] };
type Bare<T> = { readonly [K in keyof T]?: T[K] };
interface P {
x: number;
}
const a: Explicit<P> = {};
const b: Bare<P> = a; // assignable both ways: same type
const c: Explicit<P> = b;
void c;go deeper
Remember that a modifier written bare in a mapped type already adds it, so +readonly and readonly are interchangeable; only the minus form is worth memorising as a distinct thing.
Explain the symmetry argument — the plus exists so the add and remove directions read alike — and note that the standard library writes the add direction bare and reserves the sign for -?.
Do not let a review argument form around a stylistic prefix; the substantive check is whether a helper strips modifiers from a keyof T mapping at all, not how the add direction is spelled.
If your codebase ships paired helpers, pick one spelling convention and write it down, so readers never wonder whether a plus in one file implies something a bare modifier in another does not.
## The rule in one line In a mapped type, a modifier written without a sign is an *add*. The `+` sign makes that explicit and changes nothing else. ```ts type A<T> = { +readonly [K in keyof T]+?: T[K] }; type B<T> = { readonly [K in keyof T]?: T[K] }; // A<X> and B<X> describe the same type for any X ``` Only the minus form actually changes behaviour: ```ts type C<T> = { -readonly [K in keyof T]-?: T[K] }; // strips both modifiers ``` ## Why the plus exists at all The two modifiers a mapped type can control — `readonly` and the optional marker `?` — each have two directions, add and remove. The syntax needed a way to express "remove", and once `-readonly` and `-?` existed, allowing `+readonly` and `+?` gave the grammar a matching pair. Without it, the add direction would be written by *absence* of a sign while the remove direction was written by *presence* of one, which reads asymmetrically in a file that contains both helpers: ```ts type Freeze<T> = { +readonly [K in keyof T]: T[K] }; type Thaw<T> = { -readonly [K in keyof T]: T[K] }; ``` Side by side like that, the `+` earns its keep as documentation. Written alone, `+readonly` is noise, and most codebases and the standard library itself just write `readonly`. ## Where the signs go Each sign attaches to the modifier it controls, and each modifier has a fixed position: - `readonly` (and therefore `+readonly` / `-readonly`) goes **before** the `[K in ...]` bracket. - `?` (and therefore `+?` / `-?`) goes **after** the closing bracket, before the colon. Swapping those positions is a syntax error, not a subtly different type. That is worth committing to muscle memory, because the mistake shows up under pressure far more often than any conceptual confusion about the signs themselves. ## What the standard library does `lib.es5.d.ts` writes the add direction bare and only spells out the minus where it needs it: ```ts type Partial<T> = { [P in keyof T]?: T[P] }; type Readonly<T> = { readonly [P in keyof T]: T[P] }; type Required<T> = { [P in keyof T]-?: T[P] }; ``` Notice `Required` is the only one of the three that carries a sign. If you are asked to write these from memory, matching that convention is the safe answer: bare for add, explicit minus for remove. ## What it does not mean A candidate who has half-remembered the syntax sometimes reads `+?` as "add `undefined` to the type" or `+readonly` as "deep-freeze", or supposes that `+` somehow forces the modifier on even when the source property lacked it — but that last reading is exactly what plain `readonly` already does, so there is nothing extra to force. Others expect `+` and `-` to be usable on other things, like a property's type or a key name; they are not. Only `readonly` and `?` accept a sign, and the only meaningful sign is the minus. Finally, none of this survives compilation. Both modifiers, with or without a sign, are part of the type layer, and the emitted JavaScript is identical whichever spelling you choose. ## How to answer it Say "no difference — bare already means add, and `+` is the explicit form that exists so `-` has a counterpart", then show the minus version to prove you know which sign is the one that matters. That is the complete answer; padding it further usually invents a distinction that is not there.
- Which of the two signs actually changes the resulting type?Only the minus. `-readonly` and `-?` strip a modifier that the mapping copied from the source type, which is how helpers like `Mutable<T>` and the standard library's `Required<T>` work. The plus is definitionally identical to writing the modifier bare, so replacing every `+` in a codebase with nothing would leave every type unchanged.
- Can `+` or `-` be applied to anything other than `readonly` and `?` in a mapped type?No. Those two are the only modifiers a mapped type property can carry, so they are the only things a sign can attach to. You cannot sign a key name, a value type, or an access modifier. Anything else you want to change about the produced properties is expressed in the key clause or the value position instead.
saying these in an interview costs you the question
- Thinks +readonly does something stronger than plain readonly
- Reads +? as adding undefined to the property type
- Believes a bare modifier means leave unchanged
- Expects + and - to work on keys or value types too