Typescript: extending an interface and redeclaring the existing fields as readonly

心已入冬 提交于 2019-12-11 05:57:51

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/41201198/typescript-extending-an-interface-and-redeclaring-the-existing-fields-as-readon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!