Let's say we have an interface like this:
interface Person {
name: string;
age: number;
}
I want to call Readonly and create a readonly version of the interface, e.g.
interface PersonReadonly extends Readonly<Person> {}
which will be equivalent to writing
interface PersonReadonly {
readonly name: string;
readonly age: number;
}
Can we write such a Readonly generic interface, or is it written already?
You can do:
type PersonReadonly = Readonly<Person>
But it is not an interface. For example, you can't add a new member somewhere else.
Edit from May, 2017: Since TS 2.2 (February, 2017), interfaces can be derived from types.
To answer you explicit question: You technically can't do what you want yet.
Type Mapping will create a Type
not an interface -- Readonly<T>
is a built in type mapper that will return a Type
. You cannot implement or extend Type
aliases, only interface / class.
thus:
interface PersonReadonly extends Readonly<Person> {}
is invalid until support for implementing types are done, if ever.
That doesn't stop you passing around the Type though; and you can use union on types to build up more complex types too. thus you can do:
type PersonWithState = Readonly<Person> & { state: string }
let person = <Person>{ name: "John", age: 20 };
let personState = <PersonWithState>{ ...person, state: "online" };
personState.age = "30"; // error;
personState.state = "offline"; // OK.
but you cannot have a class implement, or interface extend, PersonWithState
- yet.
In playground the Readonly
type is defined so you can do:
interface Person {
name: string;
age: number;
}
let a: Readonly<Person> = {
name: "name",
age: 3
};
a.age = 5; // Error: Cannot assign to 'age' because it is a constant or a read-only property
(code in playground)
If the type is defined in your environment then you can simply add it:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
But it requires you to have typescript 2.1 and above.
If you don't have it, it probably means that your typescript version is below 2.1, otherwise you can just use it.
The generic interface for making all fields of the instance readonly
is available as of TypeScript 2.1.
It's called exactly Readonly<T>
, so you can use it like this:
let person: Readonly<Person> = { name: 'John', age: 30 };
person.age = 31; // gives error
It's impossible to implement generic readonly type before TypeScript 2.1.