codelab-kanban-fire icon indicating copy to clipboard operation
codelab-kanban-fire copied to clipboard

drop method gives compile error in strong typing scenario on step 11 of the "Building a web application with Angular and Firebase" tutorial

Open rostag opened this issue 3 years ago • 1 comments

Thanks for the great tutorial on Angular + Firebase! There's a minor typing issue appearing on step 11.

Issue Description

In particular setup (details below) the strong typing of the drop method like this won't compile (fix in the end of message):

drop(event: CdkDragDrop<Task[]>): void { ...

Compile-time error for strong-typed case looks like this:


ERROR

src/app/app.component.html:23:38 - error TS2345: Argument of type 'CdkDragDrop<Task[] | null, any, any>' is not assignable to parameter of type 'CdkDragDrop<Task[], Task[], any>'.
  The types of 'container.data' are incompatible between these types.
    Type 'Task[] | null' is not assignable to type 'Task[]'.
      Type 'null' is not assignable to type 'Task[]'.

23           (cdkDropListDropped)="drop($event)"
                                        ~~~~~~

  src/app/app.component.ts:11:16
    11   templateUrl: './app.component.html',
                      ~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component AppComponent.
...
...

Setup it was reproduced in

package.json

Details

{
  "name": "uif-client",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^14.2.0",
    "@angular/cdk": "^14.2.2",
    "@angular/common": "^14.2.0",
    "@angular/compiler": "^14.2.0",
    "@angular/core": "^14.2.0",
    "@angular/fire": "^7.4.1",
    "@angular/forms": "^14.2.0",
    "@angular/material": "^14.2.2",
    "@angular/platform-browser": "^14.2.0",
    "@angular/platform-browser-dynamic": "^14.2.0",
    "@angular/router": "^14.2.0",
    "rxjs": "~7.5.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^14.2.4",
    "@angular/cli": "~14.2.4",
    "@angular/compiler-cli": "^14.2.0",
    "@types/jasmine": "~4.0.0",
    "jasmine-core": "~4.3.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.0.0",
    "typescript": "~4.7.2"
  }
}

angular.json

Details

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "uif-client": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/uif-client",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "500kb",
                  "maximumError": "1mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "2kb",
                  "maximumError": "4kb"
                }
              ],
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "outputHashing": "all"
            },
            "development": {
              "buildOptimizer": false,
              "optimization": false,
              "vendorChunk": true,
              "extractLicenses": false,
              "sourceMap": true,
              "namedChunks": true
            }
          },
          "defaultConfiguration": "production"
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "configurations": {
            "production": {
              "browserTarget": "uif-client:build:production"
            },
            "development": {
              "browserTarget": "uif-client:build:development"
            }
          },
          "defaultConfiguration": "development"
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "uif-client: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",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
              "src/styles.css"
            ],
            "scripts": []
          }
        }
      }
    }
  },
  "cli": {
    "analytics": false
  }
}

How to fix it

Use update the signature of drop method and implementation a bit

  drop(eventMock: CdkDragDrop<Task[] | null>): void {
    if (!eventMock || (eventMock.previousContainer === eventMock.container)) {
      return;
    }
    const event = eventMock as CdkDragDrop<Task[]>;
    const item = event.previousContainer.data[event.previousIndex];
    this.store.firestore.runTransaction(() => {
      const promise = Promise.all([
        this.store.collection(event.previousContainer.id).doc(item.id).delete(),
        this.store.collection(event.container.id).add(item),
      ]);
      return promise;
    });
    transferArrayItem(
      event.previousContainer.data,
      event.container.data,
      event.previousIndex,
      event.currentIndex
    );
  }

Hope this will be helpful to community.

rostag avatar Sep 28 '22 20:09 rostag

same error

hussain4real avatar Jan 03 '23 09:01 hussain4real