What are the differences between readonly vs get in TypeScript properties?

It makes a difference to the generated JavaScript: The getter will be an accessor property (e.g., function), the readonly property will be a data property. This:

class Example {
    get foo(): string {
        return "foo";
    }
    readonly bar: string = "bar";
}

converts to this if you target ES2015+:

"use strict";
class Example {
    constructor() {
        this.bar = "bar";
    }
    get foo() {
        return "foo";
    }
}

Live on the playground

or to this if you target ES5+:

"use strict";
var Example = /** @class */ (function () {
    function Example() {
        this.bar = "bar";
    }
    Object.defineProperty(Example.prototype, "foo", {
        get: function () {
            return "foo";
        },
        enumerable: true,
        configurable: true
    });
    return Example;
}());

Live on the playground

Notice that although TypeScript considers bar read-only, nothing enforces that at runtime. foo, on the other hand, is read-only even at runtime. (Although if you really wanted to, you could use Object.defineProperty to defeat it by reconfiguring the property.)


A getter is evaluated again on every property access, and creates a new value. This is an important functional difference, as that behaviour is usually not what you want:

class Example {
    get foo(): object {
        return {};
    }
    readonly bar: object = {};
}
const example: Example = new Example;
console.log(example.foo === example.foo); // false
console.log(example.bar === example.bar); // true

For the implementation details, see @T.J.Crowder's excellent answer which I won't repeat here.