一种将模板中的变量转换为多种类型的方法

时间:2021-04-15 02:17:02

标签: angular typescript

我有一个 angular 应用程序

  "angularCompilerOptions": {
    "strictInjectionParameters": true,
    "fullTemplateTypeCheck": true,
    "strictTemplates": true
  }

所以每个输入/输出都没有经过类型检查。

它适用于大多数应用程序,但我有一些应用程序输入,例如(这里我显示选择,但我也有一个简单的 app-input 工作相同):

.html

      <app-select
        [useSearch]="true"
        [formControlName]="'country'"
        (valueChange)="setSelectedCountry($event)" <=== $event is of type unknown
      >
        <app-option
          *ngFor="let country of locations$ | async"
          [name]="'COUNTRIES.' + country.code | translate"
          [value]="country.code" <=== this is of type Country
        ></app-option>
      </app-select>

.ts

  setSelectedCountry(code: Country) {
    this.store.dispatch(loadLocationRequest({ payload: { code } }));
    this.selectedLocation$ = this.store.pipe(select(getLocationByCode(), { code }));
  }

在上面,因为我使用我的 app-select 作为具有各种值的多重选择器,所以它是类型:

  @Input()
  get value(): unknown | unknown[] {
    return this.pValue;
  }
  set value(newValue: unknown | unknown[]) {
    if (newValue !== this.pValue) {
      this.pValue = newValue;
      this.writeValue(newValue);
    }
  }

现在,我看到了 2 个解决方案,

  1. 我不会像这样使用 ngModel [(value)]="country",我创建了一个方法来检查所有使用 select 的组件:
  2. 我为我选择使用的每种类型的值创建一个类型并转换为它。

但我只想对这些情况做一些更简单的事情。

是否可以通过输入或其他方式将泛型类型传递给组件,以便它返回我传递的泛型类型? 喜欢(例如:<app-select<string>>

是否可以制作一个将 a 转换为通用值的管道?无需为每种类型制作管道? string number 等等...?

是否可以忽略某些检查?

1 个答案:

答案 0 :(得分:0)

所以,我尝试了多种方法,并且采用了一种hacky 方式,我真的不推荐,除非在某些特殊情况下(有点像 $any())。

正确的方法是:

每个未知类型都有一个管道,这样你就可以在类型内部做一些类型检查来排除

import { Pipe, PipeTransform } from '@angular/core'
import { Gender } from '@app/__generated__/globalTypes'

@Pipe({
  name: 'toAnimal',
  pure: true,
})
export class ToAnimalPipe implements PipeTransform {
  transform(value: unknown): Animal {
    return typeof value === "string" && Object.keys(Animal).includes(value) ? 
              value as Animal : 
              Animal.DOG // Default value just use anything you want.
  }
}

骇人听闻的方法:

我做了以下简单的管道:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'toType',
  pure: true,
})
export class ToTypePipe implements PipeTransform {
  transform<T>(value: unknown, _: T): T {
    return value as T;
  }
}

你可以这样称呼它

 value | toType: Animal.DOG

value 可以是 Animal 的任何值,但我们只是将 is 转换为值之一,因此编译器认为可以使用它并且不会抱怨。

这是不安全的,并且有点消除严格模式的目的。

但是,它允许做一些解决方法并使一些非常简单的演员变得容易。就像在这种情况下:

<table [dataSource]="animals"> <=== Array<Animal>
 <ng-container [cdkColumnDef]="columns.name.def">
  <td class="align-items-center p-4 w-80" cdk-cell *cdkCellDef="let element"> 

*cdkCellDef="let element" 这是一个 Animal 但角度模板不允许我们有正确的输入,所以在这种情况下 let element | typeOf: Animal.DOG 应该是完全安全的