【问题标题】:Can I do type-narrowing in an Angular template?我可以在 Angular 模板中进行类型缩小吗?
【发布时间】:2021-04-16 07:25:29
【问题描述】:

我有一个将业务对象作为输入的组件。在此组件的模板中,我想通过检查仅存在于业务对象的某些子类上的属性的值来有条件地呈现某些内容。

export class Thing { public foo: string; }
export class SubThing extends Thing { public bar: number; }

// ...
export class MyComponent {
  @Input() thing: Thing;
}

<!-- template file -->
{{ thing.foo }}
<div *ngIf="thing?.bar > 10">Conditional content...</div>

因为编译器对模板中的类型检查不是很严格,所以它以前写的那样工作。最近这开始与 AOT 编译器发生冲突(不确定具体是什么时候),因为严格来说,当编译器认为 thing 只是一个 Thing 时,thing?.bar 是无效的,并且不能确定它是一个 @ 987654326@.

我想说*ngIf="thing instanceof SubThing &amp;&amp; thing?.bar &gt; 10" 之类的话,但我不能在模板本身中使用instanceof。有没有其他方法可以从模板中检查thing 的类型,以便编译器停止抱怨? (我通过将我的输入指定为any 使构建再次工作,但如果可能的话,我当然希望我的类型检查回来。)

【问题讨论】:

    标签: angular typescript


    【解决方案1】:

    显然编译器尊重User Defined Type Guards。我只需要在我的组件中定义一个方法:

    export class MyComponent {
      // ...
      /** @internal */ isSubThing(t: Thing): t is SubThing {
        return t instanceof SubThing;
      }
    }
    

    <!-- template file -->
    {{ thing.foo }}
    <div *ngIf="isSubThing(thing) && thing?.bar > 10">
      Conditional content...
    </div>
    

    【讨论】:

    • 这似乎不再适用于 Angular 10.0.7
    • 我在 Angular 9 中使用它没有任何问题,你启用了哪些编译器标志?也许您被严格的模板检查所吸引?
    【解决方案2】:

    编辑:从 Angular 11 开始,模板中的类型保护似乎工作正常。我在下面的回答可能对运行早期版本 Ivy 的人仍然有用。

    在 Angular Ivy 中有一种方法可以通过严格的模板检查来允许在模板中缩小类型。这有点hacky,但它有效。如果它通过类型检查,则在组件中创建一个方法来返回对象,如果没有,则返回 undefined。然后,您使用 then 将该方法的结果分配给 ngIf 表达式中的新变量。新变量将是正确的类型

    export class MyComponent {
       // ...
       
       public isSubThing(t: Thing): SubThing | undefined{
           return t instanceof SubThing? t : undefined;
       }
    }
    

    <!-- template file -->
    {{ thing.foo }}
    <ng-container *ngIf="isSubThing(thing) as subThing">
        <div *ngIf="subThing.bar > 10">
          Conditional content...
        </div>
    </ng-container>
    

    这是一个堆栈闪电战:https://stackblitz.com/edit/angular-ivy-gmqkzj

    【讨论】:

    • 我最近切换到strictTemplates: true 并没有真正需要这样做。至少从版本 11.1.2 开始,打开该标志,您的代码可以在没有新变量分配的情况下编写。
    • 谢谢,我可以确认。我已经更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-03
    • 2018-02-08
    • 2019-03-09
    • 1970-01-01
    • 1970-01-01
    • 2023-02-08
    • 2020-03-14
    相关资源
    最近更新 更多