Angular 2模板中的类型检查

51

我们正在使用Angular 2和TypeScript构建应用程序。我们尽可能地在静态检查类型。有没有办法在模板中检查类型?考虑以下片段:


我们正在 Angular 2 和 TypeScript 中构建一个应用程序。我们尝试在可能的情况下静态检查类型。是否有一种方法可以在模板中检查类型?请考虑以下代码片段:
<foo [data]="dataObj"></foo>
假设在`Foo`组件中,`data`的类型为`TData`。但是默认情况下,我仍然可以传递不符合`TData`类型的`dataObj`。是否有一个Angular模板的TypeScript扩展程序,在这种情况下可以验证类型?
假设在`Foo`组件中,`data`的类型为`TData`。但默认情况下,没有任何阻止我传递不符合`TData`类型的`dataObj`。是否有 TypeScript 扩展可以在 Angular 模板中验证此类情况下的数据类型?

2
目前还没有任何“插件”可以做到这一点(您需要使用TypeScript)。 Angular2在使其代码和模板可供IDE访问方面付出了很多努力,但这是未来的事情。 - gilamran
2
经过一番思考,也许一个解决方案是使用包装函数?类似于 <foo [data]="typeCheck(expectedtype,dataObj)> </foo>",其中 expectedtype 应该与 [data] 的类型匹配。当然,这需要程序员付出更多的努力,但这是我现在能想到的唯一方法。我很快就会尝试这个方法,如果有效,我会发布一个答案。 - Scrambo
3
我知道这并不是真正的“解决方案”,但当您使用AOT编译时,模板会被编译到结果文件中,然后当那些ngfactory TS文件被转译时,任何TypeScript错误都会被发现。这与JIT编译不同,因为JIT的模板编译发生在运行时,所以没有涉及TypeScript检查。当我第一次尝试使用AOT运行我的项目时,我发现了以前未报告的各种类型错误和从模板中访问的私有变量/方法。 - dmungin
@dmungin,您能否在AOT方法中加入更多细节?当我在一个模板中访问{{foo.bar}}时,其中foo不是我的相应组件的成员,并且我使用"ng build --aot"进行编译时,什么都没有发生,一切正常。我很失望地发现VSCode不能在模板中提供自动完成功能。这种情况有任何更新吗?看着IDE所能做的所有事情,我真的认为这不可能是个大问题... - mmey
@Aluan Haddad:静态类型检查本质上是构建/编译过程的“副作用”。这正是我们想要的——在运行应用程序之前检查类型。 - jfu
显示剩余5条评论
7个回答

16
自 Angular 9 开始,解决方案是使用 Angular 编译选项的 strictTemplates 标志,参见 Strict mode 部分和 Template type checking 指南。在 tsconfig.json 文件中启用该标志:
{
    ...
    "compilerOptions": { ... },
    "angularCompilerOptions": {
        "strictTemplates": true
        ...
    }
}

原始回答:

很遗憾,目前的 Angular 版本似乎没有检查组件输入和事件类型的功能。您可以使用 AOT 编译并启用 fullTemplateTypeCheck Angular 编译器选项,该选项执行一些模板类型检查。

src/tsconfig.app.json 中启用 fullTemplateTypeCheck 选项。

{
    "compilerOptions": { ... },
    "angularCompilerOptions": {
        "fullTemplateTypeCheck": true
        ...
    }
}

使用--aot选项构建(或提供)您的项目

ng build --aot

关于输入和事件类型检查,我在angular错误跟踪器上发现了两个问题(issue1issue2)。据我所知,问题的解决取决于渲染器实现,很可能问题会在下一个版本的angular渲染器Ivy中得到解决。这里是关于在ivy渲染器中进行输入类型检查的功能请求


但这仍然没有检查组件输入,对吗?我尝试发送错误的输入,使用 ng build --aot 没有出现错误。 - UrbKr
1
@UrbKr,是的,似乎AOT编译不会强制输入类型检查。您可以在我的更新答案中找到更详细的信息。 - Valeriy Katkov
不幸的是,这也无法检查从异步管道中提取的对象的类型。 - Phil
我在我的tsconfig.json中使用了{"fullTemplateTypeCheck": true},但最终它既不能工作也不能编译HTML模板。 - Nagender Pratap Chauhan

0

引用官方声明:

在模板类型检查阶段,Angular模板编译器使用TypeScript编译器来验证模板中的绑定表达式。

当在模板绑定表达式中检测到类型错误时,模板验证会生成错误消息,类似于TypeScript编译器针对.ts文件中的代码报告类型错误的方式。

更多信息请参考:

Angular模板检查 https://angular.io/guide/aot-compiler#binding-expression-validation

要激活它,您需要构建应用程序,方法如下:

ng build --aot

或者

ng build --prod

但你也可以在不构建的情况下激活它:

ng serve --aot


0

JetbrainsWebStorm可以做到这一点。

我的原始答案:

我认为没有可靠的方法可以在不进行某些操作(例如React使用JSX或TSX扩展名)的情况下实现这一点。

TypeScript编译器不知道您的HTML文件,并且将忽略它们。此外,模板与控制器代码之间没有强耦合... 没有任何东西阻止您在多个控制器之间重用相同的模板。


现在已经有AOT,它考虑了模板。 - jfu
另外,我刚刚注意到Jetbrains的WebStorm能够检查模板中的变量类型。 - Victor Högemann

-1

您的组件Input()应该有类型。假设您有一个列表组件

import {Component, Input, OnInit } from '@angular/core';

import { Items } from '../../../services/Items';

@Component({
  selector: 'my-list',
  templateUrl: './my-list.component.html',
  styleUrls: ['./my-list.component.scss'],
})
export class CategoryListComponent implements OnInit {
  @Input() items: Items;

  constructor() { }

  ngOnInit() { }
}

"

"Items" 应该被定义为一个接口并进行导入

"
export interface List {
  name: string,
  children: Items[]
}

export interface Item {
  name: string;
  slug: string;
  imageUrl: string;
  children: Item[];
}

现在你可以像这样使用它

<my-list [items]="items"></my-list>

-1
你可以使用管道(Pipe):
export class ObjectTypePipe implements PipeTransform {
    transform(value: any, args?: any): string {
        if (value != undefined && value != null) {
            return value.constructor.name.toString();
        }
        return "";
    }
}

这将允许您进行字符串比较。

-1
如果您正在使用Visual Studio Code,可以尝试使用语言服务扩展。它仍在积极开发中,您可以将其视为测试版。但我肯定会说它让我更加高效。不仅有类型检查,还可以通过cmd + 单击组件转到它们的源代码。
如果我没记错,这个项目最终将合并到VSCode本身中,当它相对稳定时,因为保持Angular开发人员的生产力符合VSCode的最佳利益。
您可以放心使用该扩展,因为它是由Angular团队开发的。有关更多信息,请查看此自述文件编辑:Sublime Text和WebStorm也支持此功能。

-1

我认为一个IDE或linter可能会为您捕捉到这个问题,但如果有人真的需要这个,一个选项是创建一个管道,在运行时进行类型检查。

@Pipe({ name: 'typeCheck' })
export class TypeCheckPipe implements PipeTransform {

  transform(value: any, classType: object): any[] {
    if (value &&
      !(value instanceof classType)
    ) {
        throw new TypeError("Input is not instanceof " + classType + 
                            " but was " + typeof(value));
    }
    return value;
  }
}

您可以像这样在组件模板中使用它:

<custom-component [coolInput]="coolInput | typeCheck:coolInputClass"></custom-component>

我唯一发现的问题是,除了作为组件实例之外,我不确定如何将类函数注入模板中。
@Component({
  selector: 'my-app',
  template: `
  <div>
    <custom-component [coolInput]="coolInput | typeCheck:coolInputClass"></custom-component>
  </div>
  `,
})
export class App {
  coolInput: CoolInput;
  coolInputClass: object = CoolInput;

  constructor() {
    this.coolInput = "This is the wrong type";
  }
}

这里有一个 Plunker,展示了通过 Zone 抛出的工作错误消息。 https://plnkr.co/edit/WhoKSdoKUFvNbU3zWJy6?p=preview


4
这个问题是关于在静态环境下进行检查而非在运行时。 - jfu
哦,我明白了。我以为这是一个奇怪的请求。我认为你不能仅凭 TypeScript 自身来实现这个。你需要一种额外的工具来检查模板文件,因为它们不被 TypeScript 处理。比如说一个代码检查工具(linter)也许可以做到。不过,我目前还不知道有没有一种工具可以验证 Angular 2 组件输入的类型。 - kevinrstone
代码检查工具不会为你捕获这个。 - Mozgor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接