Typescript: расширение интерфейса и переопределение существующих полей как доступных только для чтения

Допустим, у нас есть такой интерфейс:

interface Person {
  name: string;
  age: number;
}

Я хочу вызвать Readonly и создать версию интерфейса только для чтения, например.

interface PersonReadonly extends Readonly<Person> {}

что будет эквивалентно написанию

interface PersonReadonly {
  readonly name: string;
  readonly age: number;
}

Можем ли мы написать такой универсальный интерфейс только для чтения, или он уже написан?


person Yavuz Mester    schedule 17.12.2016    source источник


Ответы (4)


Ты можешь сделать:

type PersonReadonly = Readonly<Person>

Но это не интерфейс. Например, вы не можете добавить нового участника в другом месте.

Изменение от мая 2017 г.: начиная с версии TS 2.2 (февраль 2017 г.) можно создавать интерфейсы. из типов.

person Paleo    schedule 17.12.2016

Чтобы ответить на ваш явный вопрос: технически вы еще не можете делать то, что хотите.

Отображение типов создаст Type, а не интерфейс — Readonly<T> — это встроенный преобразователь типов, который вернет Type. Вы не можете реализовать или расширить Type псевдонимы, только интерфейс/класс.

таким образом:

interface PersonReadonly extends Readonly<Person> {}

недействителен до поддержки реализации типов, если вообще когда-либо.

Это не останавливает вас от передачи Type; и вы можете использовать объединение типов для создания более сложных типов. таким образом, вы можете сделать:

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.

но у вас не может быть реализации класса или расширения интерфейса, PersonWithState - пока.

person Meirion Hughes    schedule 17.12.2016
comment
Есть ли способ сделать всю цепочку объектов доступной только для чтения? Например, что, если класс _1_ ссылается на другой объект? - person Daniel Earwicker; 18.12.2016

На игровой площадке определен тип Readonly, поэтому вы можете:

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

Если тип определен в вашей среде, вы можете просто добавить его:

Но для этого требуется, чтобы у вас был машинописный текст версии 2.1 и выше.
Если у вас его нет, это, вероятно, означает, что ваша версия машинописного текста ниже 2.1, в противном случае вы можете просто использовать его.

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
}

Общий интерфейс для создания всех полей экземпляра Readonly доступен с TypeScript 2.1.

person Nitzan Tomer    schedule 17.12.2016
comment
@NSjonas Вы имеете в виду что-то вроде здесь: stackoverflow.com/questions/41879327/ ? - person NSjonas; 16.09.2017

Он называется точно Readonly<T>, поэтому вы можете использовать его так:

Невозможно реализовать универсальный тип только для чтения до TypeScript 2.1.

let person: Readonly<Person> = { name: 'John', age: 30 };
person.age = 31; // gives error

NB. Конечно, вы можете написать класс, совместимый по присваиванию с типом, что является одной из интерпретаций реализации интерфейса. Единственным ограничением является то, что вы не можете сообщить компилятору, что именно так и было задумано (вы не можете объявить, что он реализует интерфейс). Но вы можете реализовать это во всех других смыслах благодаря структурной типизации.

person Yaroslav Admin    schedule 17.12.2016