Свойство «nodeQuery» не существует для типа «{}»

при попытке создать простое приложение на Angular и Apollo я наткнулся на проблему, когда пытаюсь создать приложение с использованием ng build, хотя приложение отлично работает на localhost:4200. Приложение подключается к серверу Drupal 8 GraphQL, и соединение работает.

Вот ошибка при сборке:

ERROR in app/idea-list/idea-list.component.ts(27,37): error TS2339: Property 'nodeQuery' does not exist on type '{}'. app/idea-list/idea-list.component.ts(28,36): error TS2339: Property 'loading' does not exist on type '{}'.

Это файл graphql.ts:

import {Article} from './type';
import gql from 'graphql-tag';

export const ALL_ARTICLES_QUERY = gql `
query {
   nodeQuery {
    entities {
      title: entityLabel
      ... on NodeArticle {
        body {
          value
        }
      }
    }
  }
}
`;

export interface AllArticlesQueryResponse {
    allArticles: Article[];
    loading: boolean;
}

Это результат сервера GraphQL:

{
  "data": {
    "nodeQuery": {
      "entities": [
        {
          "title": "Article title.",
          "body": {
            "value": "<p>Article body value.</p>\r\n"
          }
        }
      ]
    }
  }
}

А это файл app/idea-list/idea-list.component.ts:

import { Component, OnInit } from '@angular/core';
import { Apollo } from 'apollo-angular';
import {Article } from '../type';
import {ALL_ARTICLES_QUERY, AllArticlesQueryResponse} from '../graphql';

@Component({
  selector: 'app-articles-list',
  templateUrl: './articles-list.component.html',
  styleUrls: ['./articles-list.component.css']
})
export class ArticlesListComponent implements OnInit {

  allArticles: Article[] = [];
  loading: boolean = true;

  constructor(private apollo: Apollo) { }

  ngOnInit() {
    this.apollo.watchQuery({
        query: ALL_ARTICLES_QUERY
    }).valueChanges.subscribe((response) => {
      console.log(response);
      this.allArticles = response.data.nodeQuery.entities;
      this.loading = response.data.loading;
    });
  }
}

ОБНОВЛЕНИЕ: в консоли браузера нет ошибок, и приложение работает нормально. Однако при создании приложения (когда я что-то меняю в коде) это происходит в окне терминала:

webpack: Compiling...
Date: 2018-04-25T09:09:23.622Z - Hash: b0a12071eaf44c16d874 - Time: 626ms
4 unchanged chunks
chunk {main} main.bundle.js (main) 36.3 kB [initial] [rendered]

webpack: Compiled successfully.
ERROR in src/app/articles-list/articles-list.component.ts(22,40): error TS2339: Property 'nodeQuery' does not exist on type '{}'.
src/app/articles-list/articles-list.component.ts(23,36): error TS2339: Property 'loading' does not exist on type '{}'.

Та же ошибка не позволяет мне создать приложение (ng build).

Дополнительная информация (файлы конфигурации):

tsconfig.ts

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom",
      "esnext"
    ]
  }
}

app/tsconfig.app.json

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "baseUrl": "./",
    "module": "es2015",
    "types": []
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ]
}

package.json

{
  "name": "petiangular",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^5.2.0",
    "@angular/common": "^5.2.0",
    "@angular/compiler": "^5.2.0",
    "@angular/core": "^5.2.0",
    "@angular/forms": "^5.2.0",
    "@angular/http": "^5.2.0",
    "@angular/platform-browser": "^5.2.0",
    "@angular/platform-browser-dynamic": "^5.2.0",
    "@angular/router": "^5.2.0",
    "apollo-angular": "^1.0.1",
    "apollo-angular-link-http": "^1.0.3",
    "apollo-cache-inmemory": "^1.1.12",
    "apollo-client": "^2.2.8",
    "bootstrap": "^3.3.7",
    "core-js": "^2.4.1",
    "graphql": "^0.13.2",
    "graphql-tag": "^2.9.1",
    "rxjs": "^5.5.6",
    "zone.js": "^0.8.19"
  },
  "devDependencies": {
    "@angular/cli": "~1.7.4",
    "@angular/compiler-cli": "^5.2.0",
    "@angular/language-service": "^5.2.0",
    "@types/jasmine": "~2.8.3",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.8.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~2.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~4.1.0",
    "tslint": "~5.9.1",
    "typescript": "~2.5.3"
  }
}

.angular.cli.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "petiangular"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "../node_modules/bootstrap/dist/css/bootstrap.css",
        "styles.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "lint": [
    {
      "project": "src/tsconfig.app.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "src/tsconfig.spec.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "e2e/tsconfig.e2e.json",
      "exclude": "**/node_modules/**"
    }
  ],
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "css",
    "component": {}
  }
}

person petiar    schedule 25.04.2018    source источник
comment
Я не понимаю? все работает, даже данные на графике, но вы все равно получаете сообщение об ошибке в консоли браузера, но эта ошибка также не нарушает выполнение, и веб-сайт продолжает работать нормально? Я помогу избавиться от него, я просто хочу знать, с чем мы имеем дело.   -  person tatsu    schedule 25.04.2018
comment
Большое спасибо, @tatsu. Я обновил свой вопрос. В принципе, приложение работает нормально, в консоли нет ошибки, оно выдает ошибку только при компиляции/сборке, хотя в браузере оно работает нормально.   -  person petiar    schedule 25.04.2018
comment
ой! Ok. Я понимаю.   -  person tatsu    schedule 25.04.2018


Ответы (2)


Эта ошибка компиляции может быть вызвана многими причинами, но я подозреваю, что это происходит во время транспиляции.

И ошибка, скорее всего, связана с Drupal 8 GraphQL.

Но возможно, что, повозившись с уровнями ECMAscript и/или настройками компиляции JIT и AOT, вы сможете избавиться от этого.

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

Выполните производственную сборку и посмотрите, не станет ли небольшая заминка препятствием и приведет к сбою процесса компиляции.

Если это не так, вы можете просто сообщить об этом Drupal 8 GraphQL здесь.

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

Если это приведет к сбою рабочей компиляции, мы попробуем другие варианты компиляции.

person tatsu    schedule 25.04.2018
comment
Спасибо за вашу помощь! Как может возникнуть ошибка из D8 GQL, если предоставленные данные поступают правильно? В любом случае, как я уже упоминал выше, развертывание не работает. После запуска команды ng build --prod я получаю упомянутые выше ошибки. Папка dist не создается. - person petiar; 25.04.2018
comment
хорошо, так что ошибка фатальная при переходе на производство, как я и опасался. (а что касается ошибки, которая все еще присутствует в D8 GQL, несмотря на то, что данные поступают напрямую, я не знаю, как работает их код, но из вашего вставленного кода ошибка не кажется мне на угловом уровне). попробуйте войти в /<project>/tsconfig.json и /<project>/src/tsconfig.app.json и добавить их в свой вопрос, а также ваши полные /<project>/package.json и /<project>/.angular-cli.json - person tatsu; 25.04.2018
comment
Сделанный. Спасибо. - person petiar; 25.04.2018
comment
дерьмо, у тебя везде правильные значения x) Боюсь, здесь у меня закончились идеи. Попробуйте импортировать AfterViewInit, добавить его в раздел implements и переместить свой код из ngOnInit в ngAfterViewInit, и почему бы не добавить setTimeout(() => {your code}, 2000);, пока вы это делаете. Это может помочь подтвердить, что это связано с тем, что значение не было сохранено в одном из предыдущих вызовов. - person tatsu; 25.04.2018
comment
@petiar это stackoverflow.com/questions/48809849 - это проблема, с которой я столкнулся, о которой мне напоминает ваша проблема. как вы можете видеть, я пытался скомпилировать для производства с принудительной компиляцией JIT. может быть, вы можете попробовать это. попробуйте также возиться со всеми значениями ECMAscript, кроме target в tsconfig.json - person tatsu; 25.04.2018

Вы делаете несколько вещей неправильно, поэтому позвольте мне объяснить.

Прежде всего, это проблема с TypeScript, и она не имеет ничего общего с проблемами javascript во время выполнения, поэтому вы видите это в терминале. TypeScript предупреждает вас, что свойство nodeQuery недоступно в объекте. Это потому, что для TypeScript этот объект пустой, не имеет свойств.

import {Article} from '../type';
import {ALL_ARTICLES_QUERY, AllArticlesQueryResponse} from '../graphql';

export class ArticlesListComponent implements OnInit {

  allArticles: Article[] = [];
  loading: boolean = true;

  constructor(private apollo: Apollo) { }

  ngOnInit() {
    this.apollo.watchQuery({
        query: ALL_ARTICLES_QUERY
    }).valueChanges.subscribe((response) => {
      // response.data is {} (for typescript)
      // it means it's an empty object which has no properties
      this.allArticles = response.data.nodeQuery.entities;

      // another issues is that `loading` should be under `response` not `response.data`
      // it should be `response.loading`
      this.loading = response.data.loading;
    });
  }
}

Apollo не знает, каков интерфейс вашего результата, но позволяет вам определить его. Я вижу, у вас есть определенный интерфейс, так что давайте использовать его :)

import {Article} from '../type';
import {ALL_ARTICLES_QUERY, AllArticlesQueryResponse} from '../graphql';

export class ArticlesListComponent implements OnInit {

  allArticles: Article[] = [];
  loading: boolean = true;

  constructor(private apollo: Apollo) { }

  ngOnInit() {
    // we define it as a first generic type of watchQuery method
    this.apollo.watchQuery<AllArticlesQueryResponse>({
        query: ALL_ARTICLES_QUERY
    }).valueChanges.subscribe((response) => {
      this.allArticles = response.data.nodeQuery.entities;
      this.loading = response.loading;
    });
  }
}

Вам не нужно писать интерфейс вручную, есть инструменты, которые сделают это за вас. Прочитайте мой ответ здесь: https://stackoverflow.com/a/52454671/4035768

person Kamil Kisiela    schedule 22.09.2018