角度和异步管道打字稿抱怨为空

mat*_*ias 15 ngrx angular

我有以下容器组件

export class EventsComponent {
  data$: Observable<Data[]> = this.store.select(data);
  loading$: Observable<boolean> = this.store.select(loading);
}
Run Code Online (Sandbox Code Playgroud)

并将可观察量绑定| async到表示组件:

 <app-presentational 
   [rowData]="data$ | async" 
   [loading]="loading$ | async" 
   ...
Run Code Online (Sandbox Code Playgroud)
export class PresentComponent {
  @Input()
  rowData: Data[];

  @Input()
  loading: boolean;
}
Run Code Online (Sandbox Code Playgroud)

然而,TS 编译器总是抱怨异步管道可能返回 null。

更新,这是我得到的确切错误

Type 'boolean | null' is not assignable to type 'boolean'.
  Type 'null' is not assignable to type 'boolean'.ngtsc(2322)
Run Code Online (Sandbox Code Playgroud)

那么我真的必须改变我的一切吗@Input()

export class PresentComponent {
  @Input()
  rowData: Data[] | null;

  @Input()
  loading: boolean | null;
}
Run Code Online (Sandbox Code Playgroud)

dev*_*033 23

正如 Angular 文档在这里指出的那样:

上述问题有两种可能的解决方法:

在模板中,包含非空断言运算符 ! 在可为空表达式的末尾,例如 <user-detail [user]="user!" />。

在此示例中,编译器忽略可空性中的类型不兼容性,就像在 TypeScript 代码中一样。对于异步管道,请注意表达式需要用括号括起来,如 <user-detail [user]="(user$ | async)!" />。

完全禁用 Angular 模板中严格的 null 检查。

启用 strictTemplates 后,仍然可以禁用类型检查的某些方面。将选项 strictNullInputTypes 设置为 false 会禁用 Angular 模板中严格的 null 检查。该标志适用于属于应用程序的所有组件。

但是,您可以执行以下任一操作,而不是使用非空断言运算符,甚至禁用 Angular 严格检查:

  1. 使用 nullish 合并运算符 ( ??) - 在 Angular 12+ 中可用:

服务

@Component({
  template: ``,
})
export class PresentationalComponent {
  @Input() loading: boolean;
  @Input() rowData: Data[];
}
Run Code Online (Sandbox Code Playgroud)

HTML

<app-presentational
  [loading]="(loading$ | async) ?? false"
  [rowData]="(rowData$ | async) ?? []"
></app-presentational>
Run Code Online (Sandbox Code Playgroud)
  1. 使用ngAcceptInputType_*

服务

@Component({
  template: ``,
})
export class PresentationalComponent {
  static ngAcceptInputType_loading?: boolean | null;
  // Note that if you have `@angular/cdk` installed you can use this instead:
  // static ngAcceptInputType_loading: BooleanInput;
  static ngAcceptInputType_rowData?: Data[] | null;

  @Input() loading: boolean;
  @Input() rowData: Data[];
}
Run Code Online (Sandbox Code Playgroud)

HTML

<app-presentational
  [rowData]="rowData$ | async"
  [loading]="loading$ | async"
></app-presentational>
Run Code Online (Sandbox Code Playgroud)
  1. TS 4.3+getter :和的不同类型setter

服务

@Component({
  template: ``,
})
export class PresentationalComponent {
  @Input()
  // Note that if you have `@angular/cdk` installed you can use `BooleanInput` instead.
  set loading(loading: boolean | null | undefined) {
    this._loading = loading ?? false;
  }
  get loading(): boolean {
    return this._loading;
  }
  private _loading: Data[];

  @Input()
  set rowData(rowData: Data[] | null | undefined) {
    this.rowData = rowData ?? [];
  }
  get rowData(): Data[] {
    return this._rowData;
  }
  private _rowData: Data[] = [];
}
Run Code Online (Sandbox Code Playgroud)

请注意,现在您应该更喜欢使用选项 3 而不是选项 2,因为选项 2input setter coercion fields已被弃用