有没有办法将类型断言/注释添加到模板输入变量?

问题描述 投票:19回答:5

Background

我有一个看起来像这样的模板(我使用的是一个使用它作为重复项的基础的组件,它是p-pickList,但问题并不是特定于该组件,仅作为示例)

对于背景,假设我有一个类型Foo,我的组件有一个foos: Foo[],我把它喂给<p-pickList>属性下的[source]组件,它为它做内部*ngFor,我所要做的就是提供一个模板

 <ng-template let-foo pTemplate="item">
   ...
   {{ foo.anythingGoesHereWithNoWarningAndNoAutocomplete }}

但是,关于foo的类型信息似乎丢失了。

我是类型安全的忠实粉丝,我喜欢Intellij(或任何其他编辑)可以向我显示警告,如果在模板中我做了类似指定foo的无效属性的事情

如果我有一个常规的*ngFor,它会推断出foo的类型

<div *ngFor="let foo of foos">
  {{ foo.autoCompleteWorksInMostIDEsAsWellAsWarningIfInvalidProp }}

Questions:

  1. 是否有任何语法可以让我提示let-foo的类型? (希望大多数IDE都能识别)。
  2. 如果我不想依赖IDE,有没有办法让ng编译器类型检查foo(由let-foo声明)?

tl; dr是否有一种语法可以让我输入注释模板输入变量?例如像这样的东西组成了语法?

let-foo="$implicit as Foo"let-foo-type="Foo"

Workaround

一个愚蠢的想法是在我的组件中有一个身份功能,例如

identity(foo: Foo): Foo {
  return foo;
}

但是做

{{ identity(foo).fooProp }}

不是一个很大的进步

{{ (foo as Foo).fooProp }}

angular angular6
5个回答
4
投票

VSCode应该具有开箱即用的功能,只需在stackblitz:https://stackblitz.com/edit/angular-type-assertion?file=src/app/app.component.html中测试

enter image description here


2
投票

使用接口可以实现您提到的行为:

在ts文件中,定义一个接口:

export interface Dog {
  name: string;
  age: number;
}

在组件中定义变量:

@Component()...{
...
  mrSnuggles: Dog = {
    name: 'mrSnuggles',
    age: 10
  };
}

并在模板中:

  {{mrSnuggles.food}}

你可以看到错误(intellij idea):

enter image description here


2
投票

让我们看看角度有什么相似之处以及它是如何工作的!

<p *ngFor="let number of [{v: 101},{v: 102}, {v: 103}]">{{number.v}}</p>

我们可以在没有*魔法的情况下重写它

<ng-template ngFor let-number [ngForOf]="[{v: 101},{v: 102}, {v: 103}]">
  <p>{{number.v}}</p>
</ng-template>

没有观察者(ngDoCheck),它可以与(但ngTemplateOutlet have no typecheck)相同:

<ng-template let-number #templateRef>
  <p>{{number.v}}</p>
</ng-template>

 <ng-container *ngTemplateOutlet="templateRef; context: {$implicit: {v: 101}}"></ng-container>
 <ng-container *ngTemplateOutlet="templateRef; context: {$implicit: {v: 102}}"></ng-container>
 <ng-container *ngTemplateOutlet="templateRef; context: {$implicit: {v: 103}}"></ng-container>

或者我们可以自己创造它

// template
<button (click)=create(templateRef)>create</button>

// TS
constructor(private _viewContainerRef: ViewContainerRef) {
  }

  create(templateRef: TemplateRef<{$implicit: {v: number;}}>) {
    this._viewContainerRef.createEmbeddedView(templateRef, {$implicit: {v: 101}});
    this._viewContainerRef.createEmbeddedView(templateRef, {$implicit: {v: 102}});
    this._viewContainerRef.createEmbeddedView(templateRef, {$implicit: {v: 103}});
  }

TL; DR

模板类型检查魔法发生在viewContainerRef.createEmbeddedView内。 (例如ngFor);但它假设templateRef接受什么。

Angular可以在AOT中编译:

<p *ngFor="let num of [{v:1}, {v:2}]">
  {{num.does.not.exist.completly}}
</p>

因此,据我所知,我们应该假设模板具有哪些类型,但确实在模板实例化时进行检查(通过createEmbeddedView);


2
投票

发现此问题并提出了允许模板输入变量发布类型信息的解决方案,以便IDE可以在github here上提供更好的完成。这个功能目前正在开发中,希望它将在未来的Angular版本中出现。您现在应该在VS Code或Sublime Text中使用Angular Language Service扩展名。你可以放心扩展的支持,因为它正在由Angular团队进行。欲了解更多信息,请查看此readmedocs

正如您所提到的,它可以通过使用身份功能来实现,但它会导致严重的性能问题,并且对于不同类型维护此功能将是一团糟。


1
投票

问题是没有任何类型信息。 <ng-template let-foo pTemplate="item"> - 只是模板声明,它还没有绑定到任何类型/上下文,只是一些具有或可能具有anythingGoesHereWithNoWarningAndNoAutocomplete字段的动态类型。如果没有适当的仿制药支持,就不可能有这种类型的安全性。

© www.soinside.com 2019 - 2024. All rights reserved.