typescript ng模板类型变量

6tqwzwtp  于 2023-01-10  发布在  TypeScript
关注(0)|答案(6)|浏览(213)

父组件如何识别来自ngTemplateOutletContextlet-content类型?现在{{content.type}}工作正常,但IDE显示:
未解析变量类型
我如何才能将其键入为Video

父组件ts:

export interface Video {
  id: number;
  duration: number;
  type: string;
}

public videos: Video = [{id: 1, duration: 30, type: 'documentary'}];

父组件.html:

<ul>
  <li *ngFor="let video of videos">
    <tile [bodyTemplate]="tileTemplate" [content]="video"></app-card>
  </li>
</ul>

<ng-template #tileTemplate let-content>
  <h5 class="tile__type">{{content.type}}</h5>
</ng-template>

平铺组件ts:

@Component({
  selector: 'tile',
  templateUrl: './tile.component.html',
  styleUrls: ['./tile.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CardComponent {
  @Input() tileTemplate: TemplateRef<any>;
  @Input() content: Video;
}

分块.组件.html:

<div
...
  <ng-container
    [ngTemplateOutlet]="tileTemplate"
    [ngTemplateOutletContext]="{ $implicit: content }">
  </ng-container>
...
</div>
h5qlskok

h5qlskok1#

let-*变量没有类型推断。let-上下文是Angular的微语法分析器的一部分,IDE无法推断类型,因为没有明确的来源。
https://gist.github.com/mhevery/d3530294cff2e4a1b3fe15ff75d08855
您可以尝试使用$any()使IDE警告静音
https://angular.io/guide/template-syntax#the-any-type-cast-function

<ng-template #tileTemplate let-content>
  <h5 class="tile__type">{{$any(content).type}}</h5>
</ng-template>

您可以使用函数 * 强制 * 类型推断

<ng-template #tileTemplate let-content>
  <h5 class="tile__type">{{toVideo(content).type}}</h5>
</ng-template>

public toVideo(value: any): Video { return value as Video; }
c9qzyr3d

c9qzyr3d2#

我创建了一个helper指令来解决这个问题。

import { Directive, Input, TemplateRef } from '@angular/core';

@Directive({selector: 'ng-template[typedTemplate]'})
export class TypedTemplateDirective<TypeToken> {

  // how you tell the directive what the type should be
  @Input('typedTemplate')
  typeToken: TypeToken;

  // the directive gets the template from Angular
  constructor(private contentTemplate: TemplateRef<TypeToken>) {
  }

  // this magic is how we tell Angular the context type for this directive, which then propagates down to the type of the template
  static ngTemplateContextGuard<TypeToken>(dir: TypedTemplateDirective<TypeToken>, ctx: unknown): ctx is TypeToken{ return true; }
}

像这样使用它

<!-- typedTemplate is the directive, typeToken is an object on our component -->
<ng-template #someTemplate [typedTemplate]="typeToken" let-param="param">
  {{param}}
</ng-template>

并且在组件中

// here we create typeToken. the value doesn't matter as it's never used, but the type of this variable defines the types of all template parameters. 
typeToken: { param: string };
zdwk9cvp

zdwk9cvp3#

有一个简单的解决方案可以让IDE运行沿着并使用用户定义的类型保护实现代码完成:
在类中创建一个函数,该函数将变量作为参数并返回相同的变量:

export class CardComponent {
  ...
  public video = (item: Video) => item;
}

现在只需使用以下函数将变量 Package 在模板中:

<h5 class="tile__type">{{video(content).type}}</h5>
wvt8vs2t

wvt8vs2t4#

    • 一个没有创建新指令的解决方案**,这是另一个与@Reacangular非常相似的解决方案。
    • 这个问题可以通过将变量 Package 在另一个ng-template中来解决**,但我更喜欢其他解决方案,因为它只是在HTML中多添加了2行代码,当然,如果您只使用变量1或2次,@Reactangular answer会更好。

而不是这个:

<ng-template *ngTemplateOutlet="foo; context: {$implicit: {fooProp: 'Hello!'}}"></ng-template>
<ng-template #foo let-args>
    This is untyped: {{ args.fooProp }}<br>
</ng-template>

请执行以下操作:
x一个一个一个一个x一个一个二个x
当使用*ngFor*ngIf时,类型Assert为noticed by the IDE。这种解决方案的缺点是内部<ng-template>由于[ngIf]而稍后呈现。
现在,如果你在上下文中添加了一个无效的属性,你会得到下面的编译错误,here's a stackblitz demo
类型"Foo"上不存在属性"newFooProp"。
正如评论中所说,就像被接受的答案一样;此解决方案在每个生命周期中都需要调用ngZone,建议仅在与ChangeDetectionStrategy.OnPush一起使用时使用。

ylamdve6

ylamdve65#

您可以使用 * ngIf和函数键入任何模板变量

<ng-container *ngIf="asMyType(anyType) as myType">
  <!-- myType is typed here -->
</ng-container>
const asMyType = (something: unknown) => something as myType;

因此,您可以在ng-template中应用相同的方法来输入变量

<ng-template let-my-type="my-type">
  <ng-container *ngIf="asMyType(my-type) as myType">
    <!-- myType is typed here -->
  </ng-container>
</ng-template>
5lhxktic

5lhxktic6#

@Reactgular的解决方案并不是一个真正的解决方案。你不能在HTML中使用函数调用--每次HTML被重新呈现时,函数都会执行。这对性能来说是很糟糕的。
关于其他的解决方案,直接的方法是从@LordBlackhole开始的。

相关问题