You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Angular 15后AppComponent不存在selectedIndex属性的问题求助

问题描述

我有一个基于Ionic 6和Capacitor的应用,已将Angular版本升级至15.1.0,相关依赖配置如下:

"dependencies": {
  "@angular/common": "^15.1.0",
  "@angular/core": "^15.1.0",
  "@angular/forms": "^15.1.0",
  "@angular/platform-browser": "^15.1.0",
  "@angular/platform-browser-dynamic": "^15.1.0",
  "@angular/router": "^15.1.0",
  "@capacitor-community/admob": "^4.0.0",
  "@capacitor/android": "^4.6.1",
  "@capacitor/app": "4.1.1",
  "@capacitor/core": "4.6.1",
  "@capacitor/haptics": "4.1.0",
  "@capacitor/keyboard": "4.1.0",
  "@capacitor/share": "^4.1.0",
  "@capacitor/status-bar": "4.1.1",
  "@ionic-native/sqlite": "^5.36.0",
  "@ionic-native/sqlite-porter": "^5.36.0",
  "@ionic/angular": "^6.4.2",
  "@ionic/storage-angular": "^3.0.6",
  "cordova-sqlite-storage": "^6.1.0",
  "ionicons": "^6.0.4",
  "localforage-cordovasqlitedriver": "^1.8.0",
  "rxjs": "~7.8.0",
  "tslib": "^2.4.1",
  "zone.js": "~0.12.0"
},
"devDependencies": {
  "@angular-devkit/build-angular": "^15.1.0",
  "@angular-eslint/builder": "~15.1.0",
  "@angular-eslint/eslint-plugin": "~15.1.0",
  "@angular-eslint/eslint-plugin-template": "~15.1.0",
  "@angular-eslint/template-parser": "~15.1.0",
  "@angular/cli": "^15.1.0",
  "@angular/compiler": "^15.1.0",
  "@angular/compiler-cli": "^15.1.0",
  "@angular/language-service": "^15.1.0",
  "@capacitor/cli": "4.6.1",
  "@ionic/angular-toolkit": "^7.0.0",
  "@types/jasmine": "~4.3.1",
  "@types/jasminewd2": "~2.0.10",
  "@types/node": "^18.11.18",
  "@typescript-eslint/eslint-plugin": "5.48.1",
  "@typescript-eslint/parser": "5.48.1",
  "eslint": "^8.31.0",
  "eslint-plugin-import": "2.27.4",
  "eslint-plugin-jsdoc": "39.6.4",
  "eslint-plugin-prefer-arrow": "1.2.3",
  "jasmine-core": "~4.5.0",
  "jasmine-spec-reporter": "~7.0.0",
  "karma": "~6.4.1",
  "karma-chrome-launcher": "~3.1.1",
  "karma-coverage": "~2.2.0",
  "karma-coverage-istanbul-reporter": "~3.0.3",
  "karma-jasmine": "~5.1.0",
  "karma-jasmine-html-reporter": "^2.0.0",
  "protractor": "~7.0.0",
  "ts-node": "~10.9.1",
  "typescript": "~4.9.4"
}

应用侧边菜单代码如下:

app.component.html

<ion-app>
  <ion-split-pane contentId="main-content">
    <ion-menu contentId="main-content" type="overlay">
      <ion-content>
        <ion-list id="inbox-list">
          <ion-menu-toggle auto-hide="false" *ngFor="let p of appPages; let i = index">
            <ion-item (click)="selectedIndex = i" routerDirection="root" [routerLink]="[p.url]" lines="none"
              detail="false" [class.selected]="selectedIndex == i">
              <ion-icon slot="start" [ios]="p.icon" [md]="p.icon" color="secondary"></ion-icon>
              <ion-label>{{ p.title }}</ion-label>
            </ion-item>
          </ion-menu-toggle>
        </ion-list>
      </ion-content>
    </ion-menu>
    <ion-router-outlet id="main-content"></ion-router-outlet>
  </ion-split-pane>
</ion-app>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor() { }

  appPages = [
    {
      title: 'Calculate',
      url: '',
      icon: 'calculator-sharp'
    },
    {
      title: 'Favorites',
      url: '/favorites',
      icon: 'star-sharp'
    },
    {
      title: 'Settings',
      url: '/settings',
      icon: 'settings-sharp'
    },
  ];
}

升级后侧边菜单的selectedIndex属性失效,控制台报错:

[ng] Error: src/app/app.component.html:7:32 - error TS2339: Property 'selectedIndex' does not exist on type 'AppComponent'.
[ng]
[ng] 7             <ion-item (click)="selectedIndex = i" routerDirection="root" [routerLink]="[p.url]" lines="none"
[ng]                                  ~~~~~~~~~~~~~
[ng]
[ng]   src/app/app.component.ts:5:16
[ng]     5   templateUrl: 'app.component.html',
[ng]                      ~~~~~~~~~~~~~~~~~~~~
[ng]     Error occurs in the template of component AppComponent.
[ng]
[ng]
[ng] Error: src/app/app.component.html:8:48 - error TS2339: Property 'selectedIndex' does not exist on type 'AppComponent'.
[ng]
[ng] 8               detail="false" [class.selected]="selectedIndex == i">
[ng]                                                  ~~~~~~~~~~~~~
[ng]
[ng]   src/app/app.component.ts:5:16
[ng]     5   templateUrl: 'app.component.html',
[ng]                      ~~~~~~~~~~~~~~~~~~~~
[ng]     Error occurs in the template of component AppComponent.

我查阅了Angular 15迁移指南,未找到相关说明,请问为何selectedIndex不再生效?

更新:附上angular.json配置

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "app": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "prefix": "app",
      "schematics": {},
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "www",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "assets": [
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "assets"
              },
              {
                "glob": "**/*.svg",
                "input": "node_modules/ionicons/dist/ionicons/svg",
                "output": "./svg"
              }
            ],
            "styles": ["src/theme/variables.scss", "src/global.scss"],
            "scripts": [],
            "aot": false,
            "vendorChunk": true,
            "extractLicenses": false,
            "buildOptimizer": false,
            "sourceMap": true,
            "optimization": false,
            "namedChunks": true
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                }
              ]
            },
            "ci": {
              "progress": false
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "app:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "app:build:production"
            },
            "ci": {
              "progress": false
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "app:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "styles": [],
            "scripts": [],
            "assets": [
              {
                "glob": "favicon.ico",
                "input": "src/",
                "output": "/"
              },
              {
                "glob": "**/*",
                "input": "src/assets",
                "output": "/assets"
              }
            ]
          },
          "configurations": {
            "ci": {
              "progress": false,
              "watch": false
            }
          }
        },
        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "lintFilePatterns": [
              "src/**/*.ts",
              "src/**/*.html"
            ]
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "app:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "app:serve:production"
            },
            "ci": {
              "devServerTarget": "app:serve:ci"
            }
          }
        }
      }
    }
  },
  "cli": {
    "schematicCollections": [
      "@ionic/angular-toolkit"
    ],
    "analytics": false
  },
  "schematics": {
    "@ionic/angular-toolkit:component": {
      "styleext": "scss"
    },
    "@ionic/angular-toolkit:page": {
      "styleext": "scss"
    }
  }
}

解决方案

这不是Angular 15的特性变更问题,而是Angular严格模板检查的要求:

之前的Angular版本中,模板里直接赋值selectedIndex = i时,Angular会隐式在组件类上创建这个属性,但在升级后的环境中(可能是启用了更严格的类型检查,或是Angular 12+默认强化了严格模式),不允许这种隐式属性创建,必须在组件类中显式声明selectedIndex。

修改app.component.ts,添加selectedIndex属性并初始化:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  selectedIndex = 0; // 显式声明并初始化,默认选中第一个菜单

  constructor() { }

  appPages = [
    {
      title: 'Calculate',
      url: '',
      icon: 'calculator-sharp'
    },
    {
      title: 'Favorites',
      url: '/favorites',
      icon: 'star-sharp'
    },
    {
      title: 'Settings',
      url: '/settings',
      icon: 'settings-sharp'
    },
  ];
}

这样就能解决TS2339错误,同时selectedIndex的选中状态逻辑也能正常工作。

另外,建议检查项目的tsconfig.json中的strictTemplates配置,该选项开启后会强制模板中的所有属性必须在组件类中显式声明,这也是升级后报错的核心原因——之前可能该选项未开启,升级后默认启用或是被配置为开启状态。


内容的提问来源于stack exchange,提问作者Fearcoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:45:36