Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Document readonly #323

Merged
merged 4 commits into from
Jun 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions pages/Classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,27 +216,43 @@ let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // Error: The 'Person' constructor is protected
```

# Readonly modifier

You can make properties readonly by using the `readonly` keyword.
Readonly properties must be initialized at their declaration or in the constructor.

```ts
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor (theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.
```

## Parameter properties

In our last example, we had to declare a protected member `name` and a constructor parameter `theName` in the `Person` class, and we then immediately set `name` to `theName`.
In our last example, we had to declare a readonly member `name` and a constructor parameter `theName` in the `Octopus` class, and we then immediately set `name` to `theName`.
This turns out to be a very common practice.
*Parameter properties* let you create and initialize a member in one place.
Here's a further revision of the previous `Animal` class using a parameter property:
Here's a further revision of the previous `Octopus` class using a parameter property:

```ts
class Animal {
constructor(private name: string) { }
move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {
}
}
```

Notice how we dropped `theName` altogether and just use the shortened `private name: string` parameter on the constructor to create and initialize the `name` member.
Notice how we dropped `theName` altogether and just use the shortened `readonly name: string` parameter on the constructor to create and initialize the `name` member.
We've consolidated the declarations and assignment into one location.

Parameter properties are declared by prefixing a constructor parameter with an accessibility modifier.
Using `private` for a parameter property declares and initializes a private member; likewise, the same is done for `public` and `protected`.
Parameter properties are declared by prefixing a constructor parameter with an accessibility modifier or `readonly`, or both.
Using `private` for a parameter property declares and initializes a private member; likewise, the same is done for `public`, `protected`, and `readonly`.

# Accessors

Expand Down Expand Up @@ -293,7 +309,12 @@ if (employee.fullName) {

To prove to ourselves that our accessor is now checking the passcode, we can modify the passcode and see that when it doesn't match we instead get the message warning us we don't have access to update the employee.

Note: Accessors require you to set the compiler to output ECMAScript 5 or higher.
A couple of things to note about accessors:

First, accessors require you to set the compiler to output ECMAScript 5 or higher.
Downlevelling to ECMAScript 3 is not supported.
Second, accessors with a `get` and no `set` are automatically inferred to be `readonly`.
This is helpful when generating a `.d.ts` file from your code, because users of your property can see that they can't change it.

# Static Properties

Expand Down
55 changes: 55 additions & 0 deletions pages/Interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,49 @@ function createSquare(config: SquareConfig): { color: string; area: number } {
let mySquare = createSquare({color: "black"});
```

# Readonly properties

Some properties should only be modifiable when an object is first created.
You can specify this by putting `readonly` before the name of the property:

```ts
interface Point {
readonly x: number;
readonly y: number;
}
```

You can construct a `Point` by assigning an object literal.
After the assignment, `x` and `y` can't be changed.

```ts
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
```

TypeScript comes with a `ReadonlyArray<T>` type that is the same as `Array<T>` with all mutating methods removed, so you can make sure you don't change your arrays after creation:

```ts
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
```

On the last line of the snippet you can see that even assigning the entire `ReadonlyArray` back to a normal array is illegal.
You can still override it with a type assertion, though:

```ts
a = ro as number[];
```

## `readonly` vs `const`

The easiest way to remember whether to use readonly or const is to ask whether you're using it on a variable or a property.
Variables use `const` whereas properties use `readonly`.

# Excess Property Checks

In our first example using interfaces, TypeScript let us pass `{ size: number; label: string; }` to something that only expected a `{ label: string; }`.
Expand Down Expand Up @@ -282,6 +325,18 @@ interface NumberDictionary {
}
```

Finally, you can make index signatures readonly in order to prevent assignment to their indices:

```ts
interface ReadonlyStringArray {
readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!
```

You can't set `myArray[2]` because the index signature is readonly.

# Class Types

## Implementing an interface
Expand Down
2 changes: 2 additions & 0 deletions pages/Variable Declarations.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ kitty.numLives--;
```

Unless you take specific measures to avoid it, the internal state of a `const` variable is still modifiable.
Fortunately, TypeScript allows you to specify that members of an object are `readonly`.
The [chapter on Interfaces](./Interfaces.md) has the details.

# `let` vs. `const`

Expand Down