Объяснение
Комментарий JB ударяет по голове: вы получаете ошибку TypeScript, потому что any[]
type не имеет data
свойство ;по определению, any[]
ожидает что-нибудь , с единственным ограничением, что вход должен быть объектом типа Array
.
Но почему ошибка в build --prod
, а неserve
?
Вы получаете сообщение об ошибке ng build --prod
и , а не на ng serve
, потому что в среде Angular по умолчанию применяется strict
(как в "строгом соблюдении режима ввода текста").и синтаксис ") для --prod
, но не не обеспечивает strict
в локальной среде разработчика.Это сделано для того, чтобы вы могли поиграть и разобраться во всем, когда разрабатываете локально, где небрежный синтаксис менее важен, прежде чем приступить к очистке кода для производственного использования.Мне тоже понадобилось немного обдумать это, но это хорошо (тм): P
Обоснование
JavaScript позволяет вам делать практически все, что вы хотите: он имеетне знаю, как будет выглядеть res
, но предполагается, что вы знаете, что делаете, и если вы скажете, что res
будет иметь свойство с именем data
, оно просто катится с ним.
Это замечательно, если у вас небольшой проект, или если вы единственный человек, который когда-либо будет над ним работать, но он начинает становиться сложнее, когда проект становится больше, или еслиу вас есть несколько разработчиков, отправляющих код. Вы знаете, что res
обладает свойством data
, но как Саманта знает, что?
Введите TypeScript
TypeScript - это JavaScript ... с типами.Типы обеспечивают форму данного объекта, поэтому все участники (включая транспортер TypeScript) знают, в чем дело.Когда вы говорите res: any[]
, TS слышит, что «объект res
будет Object
типа Array
»;мы еще не , однако, сказали TS что-нибудь о элементах-членах в массиве, и поскольку он не знает, что вида массива res
будет, единственные вещи, к которым у нас есть доступ, - это обобщенные методы и свойства самого типа Array
.
Исправление
Итак, что нам нужносделать вместо из (res: any[])
, чтобы заставить this.users = res.data.result;
работать?
Определить интерфейс для объекта ResponseObject
Нам нужно начать с того, чтобы сказать TS, чего ожидать с небольшимболее подробно:
export interface ResponseObject {
data: {
result: {};
}
}
Теперь TS знает, что есть Object
с именем ResponseObject
, который имеет (как минимум) свойство data
, и что свойство data
равно Object
, который имеет (опять же, как минимум) свойство с именем result
.
Скажите TypeScript ожидать нашего ResponseObject
Мы можем подключить это к нашему вызову подписки следующим образом:
.subscribe( (res: ResponseObject) => {
this.users = res.data.result; // now it totally DOES like the .data.result part in build --prod!
console.log(this.users);
});
Секундочку ...
Вы можете заметить, что res
больше не является объектомpe Array
;исходя из кода, который вы опубликовали, и того факта, что вы сказали, что он работает через ng serve
, похоже, что вы ожидаете один ResponseObject, который доставит массив UserObjects в качестве полезной нагрузки для свойства data.result
;в этом случае приведенный выше пример кода должен работать нормально.
Если, однако, наш .get()
действительно равен , возвращая массив объектов ResponseObjects, мы собираемсянужно проделать дополнительную работу.
Работа с массивом ResponseObjects
Давайте сначала изменим наше объявление интерфейса:
export interface ResponseObject {
status: number; /* It's OK to exclude things we don't need,
but, the status property is going to come in handy when
we eventually want to write a catch statement for cases
when the call returns an error instead of the data we
wanted */
data: {
/* you can also split up your interface declarations to
make them easier to read; this has the added benefit of
allowing us to more easily access the sub-properties of
our payload later on */
result: UserObject; /* we're expecting a single
UserObject per ResponseObject in this scenario,
otherwise we'd use: */
// result: UserObject[];
}
}
export interface UserObject {
/* remember to use the generic type names (lowercase 'string'),
not Primitives (Capitalized 'String') in your interface
declaration, otherwise you'll get more errors */
id: number;
name: string;
email?: string; /* the question mark lets you define a
property that *may* exist, but may not. Useful if your
target API only includes parameters with non-null values
in the ResponseObject */
// ...all the other things you want and think will exist
}
Затем мы можем перепутать нашу подпискуПозвоните:
.subscribe(
// we tell subscribe that we're expecting an array of ResponseObjects
(res: ResponseObject[]) => {
/* users needs to be defined as an array to hold onto
multiple UserObjects; we're clearing it here to make
sure we're only dealing with fresh data and specifying
that it will be an array of type UserObject */
this.users: UserObject = [];
/* the data property isn't a property of the *array*, but
of each array *member-item*, so we need a loop */
res.forEach(
(res_item: ResponseObject) => {
// add the response object data to our users array
this.users.push(res_item.data.result);
});
// now console log should properly show our array of UserObjects!
console.log(this.users);
}
);
nb, Пожалуйста, не забудьте пометить это как Принятый ответ, если он действительно удовлетворительно ответит на ваш вопрос.Если кто-то приходит с лучшим или более кратким ответом на ваш вопрос, вы всегда можете изменить принятый ответ после факта.
Cheers!