Я работаю над веб-приложением в Angular и делаю следующий вызов службы
return this.http.get<SiteContent>(this.apiUrl + this.endpoint + id)
Проблема в том, что JSON, который сопоставляется с интерфейсом SiteContent, содержит объект в одном из этих полей, где содержимое непредсказуемо. Как я могу обработать это в своем коде, чтобы иметь доступ к этим полям в поле siteContent
? в идеале я хочу сделать что-то вроде этого
return this.http.get<SiteContent>(this.apiUrl + this.endpoint + id).subscribe((obj) => {
console.info(obj.siteContent.get("randomKey"));
})
Приведенный выше пример приводит к следующему сообщению об ошибке, когда я пытаюсь выполнить get() по ключу.
ERROR TypeError: obj.siteContent.get is not a function
Интерфейс SiteContent
export interface SiteContent {
id: string;
name: string;
siteContent: Map<string,string>
}
Пример JSON
{"id":"abc123","name":"name name","siteContent":{"random1":"hi","random2":"hey"}}
🤔 А знаете ли вы, что...
Один из ключевых принципов Angular - это двунаправленное связывание данных, которое автоматически обновляет интерфейс при изменении данных и наоборот.
Фон JavaScript, не относящийся к TypeScript:
JSON — это формат данных, основанный на нотации JavaScript литерал объекта. Когда вы используете метод JSON.parse()
для десериализации строки JSON в значение JavaScript, вы получите тот же тип объектов, что и с литералами объектов JavaScript:
let foo = { "a": 1, "b": "two", "c": false };
console.info(foo) // { "a": 1, "b": "two", "c": false }
let bar = JSON.parse('{ "a": 1, "b": "two", "c": false }');
console.info(bar) // { "a": 1, "b": "two", "c": false }
Объекты в JavaScript представляют собой пары ключ-значение, где ключи (обычно) являются строками, но значения могут быть любого типа. Эти ключи не нужно объявлять заранее, что касается JavaScript. Все объекты в JavaScript являются объектами «expando»..
Вы получаете доступ к свойству объекта либо с помощью записи через точку (если имя ключа является известным допустимым идентификатором):
foo.a;
или с помощью записи в квадратных скобках (обычно только в том случае, если имя ключа не является допустимым идентификатором или если оно является результатом некоторого выражения):
foo["a"];
const k = "a";
foo[k];
Вы не используете get()
для доступа к свойствам таких объектов. Существует являетсякласс JS Map
, который хранит пары ключ-значение и имеет метод get()
для извлечения таких пар. Но Map
не то же самое, что простой объект JS. Есть причины использовать Map
s, но обработка десериализованного JSON обычно не входит в их число.
Поэтому во время выполнения у вас должен быть такой код:
let json = JSON.parse(
'{"id":"abc123","name":"name name","siteContent":{"random1":"hi","random2":"hey"}}'
);
console.info(json.siteContent.random1); // hi
TypeScript добавляет статическую систему типов для описания JavaScript. Как правило, он не добавляет никакой функциональности и не меняет способ работы JavaScript. Тип interface
, например SiteContent
, — это способ описания формы определенных объектов JavaScript, с которыми вы ожидаете взаимодействовать во время выполнения.
Типы объектов в TypeScript могут иметь известные свойства с определенными ключами строкового литерала, например id
или name
. Однако также часто используются объекты JavaScript в качестве объектов Expando, где свойства имеют известный тип значения, но ключи не известны заранее. Итак, TypeScript позволяет вам присвоить типу объекта подпись индекса. Тип объекта {[k: string]: number}
означает, что «вы можете индексировать этот объект с любым ключом k
типа string
, и если там есть свойство, оно будет типа number
. В вашем случае вы хотите, чтобы свойство siteContent
было типом объекта, ключи произвольны, но значения которых равны string
s:
interface SiteContent {
id: string;
name: string;
siteContent: { [k: string]: string }
}
Вооружившись этой сигнатурой индекса, ваш код теперь будет компилироваться в TypeScript без ошибок:
let json = JSON.parse(
'{"id":"abc123","name":"name name","siteContent":{"random1":"hi","random2":"hey"}}'
) as SiteContent;
console.info(json.siteContent.random1); // hi
Ссылка на код для игровой площадки