最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why does TypeScript throw an error when accessing errorCode on t.error in Angular? - Stack Overflow

programmeradmin2浏览0评论

I'm using Angular with @ngneat/query and RxJS to handle API requests. In my code, I throw an object containing an errorCode, but TypeScript complains that errorCode does not exist on t.error.

I have the following HTML:

<div *ngIf="todos | async as todos">
  <div *ngIf="todos.error">error code: {{ todos.error.errorCode }}</div>
</div>

And in my TypeScript code:

this.todos.subscribe((t) => {
  const errorCode = t.error?.errorCode; // TypeScript error here
});

Error:

NG9: Property 'errorCode' does not exist on type 'Error'.

Code Example

Here’s the full reproducible example:
StackBlitz

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { of, tap } from 'rxjs';
import { injectQuery } from '@ngneat/query';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [CommonModule],
  template: `
    <div *ngIf="todos | async as todos">
      <div *ngIf="todos.error">error code: {{ todos.error.errorCode }}</div>
    </div>
  `,
})
export class App {
  #query = injectQuery();

  todos = this.#query({
    queryKey: ['todos'],
    queryFn: () =>
      of({ data: { status: 500 } }).pipe(
        tap((response) => {
          if (response.data.status === 500) {
            throw { errorCode: response.data.status };
          }
        })
      ),
  }).result$;

  ngOnInit() {
    this.todos.subscribe((t) => {
      const errorCode = t.error?.errorCode; // TypeScript error here
    });
  }
}

bootstrapApplication(App);

What I've Tried

  • I verified that the error is indeed an object ({ errorCode: number }) when thrown.
  • TypeScript seems to assume t.error is of type Error, which doesn't have errorCode.

Why is TypeScript treating t.error as Error, and how can I correctly type it so that errorCode is recognized?

I'm using Angular with @ngneat/query and RxJS to handle API requests. In my code, I throw an object containing an errorCode, but TypeScript complains that errorCode does not exist on t.error.

I have the following HTML:

<div *ngIf="todos | async as todos">
  <div *ngIf="todos.error">error code: {{ todos.error.errorCode }}</div>
</div>

And in my TypeScript code:

this.todos.subscribe((t) => {
  const errorCode = t.error?.errorCode; // TypeScript error here
});

Error:

NG9: Property 'errorCode' does not exist on type 'Error'.

Code Example

Here’s the full reproducible example:
StackBlitz

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { of, tap } from 'rxjs';
import { injectQuery } from '@ngneat/query';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-root',
  imports: [CommonModule],
  template: `
    <div *ngIf="todos | async as todos">
      <div *ngIf="todos.error">error code: {{ todos.error.errorCode }}</div>
    </div>
  `,
})
export class App {
  #query = injectQuery();

  todos = this.#query({
    queryKey: ['todos'],
    queryFn: () =>
      of({ data: { status: 500 } }).pipe(
        tap((response) => {
          if (response.data.status === 500) {
            throw { errorCode: response.data.status };
          }
        })
      ),
  }).result$;

  ngOnInit() {
    this.todos.subscribe((t) => {
      const errorCode = t.error?.errorCode; // TypeScript error here
    });
  }
}

bootstrapApplication(App);

What I've Tried

  • I verified that the error is indeed an object ({ errorCode: number }) when thrown.
  • TypeScript seems to assume t.error is of type Error, which doesn't have errorCode.

Why is TypeScript treating t.error as Error, and how can I correctly type it so that errorCode is recognized?

Share Improve this question asked Feb 14 at 15:43 JonJon 3233 silver badges10 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 1

First, don't throw non-Errors. Yes, it's possible. But it violates expectations and it will blow up on you at some unspecified time in the future. Instead, make a custom error class:

class MyError extends Error {
    constructor(message: string, public errorCode: number) {
        super(message);
    }
}

I've done this for HTTP errors (so I can attach the HTTP response status code) in basically every TS codebase I've ever worked in.

But since literally anything can be thrown (seriously, try throw undefined sometime and watch all hell break loose), you will need to convince (both the compiler and yourself) that a caught value is of the appropriate type:

} catch(err: unknown) {
  if (err instanceof MyError) {
    console.log(err.errorCode); // no problem
  }
}

Alternatively for more flexibility you can use a type predicate instead of the instanceof check:

function isMyError(x: unknown): x is MyError { // note the 'is'
  return Boolean(
    x 
    && typeof x === 'object' 
    && 'errorCode' in x 
    && typeof x.errorCode === 'number' 
    && 'message' in x 
    && typeof x.message === 'string'
  );
}

Playground

发布评论

评论列表(0)

  1. 暂无评论