在 Angular 1.5 中绑定组件函数时如何利用打字稿?

Posted

技术标签:

【中文标题】在 Angular 1.5 中绑定组件函数时如何利用打字稿?【英文标题】:How do I take advantage of typescript when binding a component function in angular 1.5? 【发布时间】:2016-11-02 15:47:23 【问题描述】:

我在关注this best practices guide 的同时尝试学习打字稿,但我觉得我在这里遗漏了一些东西。

这是一个使用打字稿编写的工作代码。困扰我的是,我觉得我们在这里并没有真正利用打字稿。如果有人在哪里更改函数的签名,那么编译器就不会注意到它。

让我解释一下:

首先让我们定义一个“事物”:

// thing.interface.ts
export interface IThing 
  name: string,
  id: number,

某些组件是事物的列表:

// listOfThings.component.ts
import ListOfThingCtrl from './listOfThings.controller.ts'
const listOfThings = 
  bindings: 
    things: '<',
  ,
  controller: ListOfThingCtrl,
  template: `
  <p> list of things: <p>
  <ul>
    <li ng-repeat="thing in $ctrl.things">
      <thing thing="thing" on-delete="$ctrl.deleteThing($event)"></thing>
    </li>
  </ul>
  `,

我们有一个thing 组件:

import ThingCtrl from './thing.controller.ts'

const thing = 
  bindings: 
    onDelete: '&',
    thing: '<',
  ,
  controller: ThingCtrl,
  template: `
  <p>
    thing: $ctrl.thing.name
    <a ng-click='$ctrl.deleteThing()' >
      Delete me
    </a>
  </p>
  `,

到目前为止一切顺利。

现在让我们定义控制器:

//listOfThings.controller.js
import IThing from './thing.interface.ts'

export default class ListOfThingCtrl 
  private things: Array<IThing>

  public deleteThing (thing: IThing): void 
    const i = this.things.map(t => t.id).indexOf(thing.id)
    if (i > -1) 
      this.things.splice(i, 1)
    
  



// thing.controller.js
import IThing from './thing.interface.ts'

export default class ThingCtrl 
  private thing: IThing

  // This line looks dangerous to me : this should be imported, not declared !
  private onDelete: (e: $event: IThing) => void // What now if the bounded function were to change ?

  public deleteThing (): void 
    this.onDelete($event: this.thing)
  

这段代码“有效”:它加载、编译而不会抱怨,单击“删除我”实际上会从控制器列表“事物”中删除一个“事物”

现在困扰我的是:在这段代码中,我们向thing 组件注入了一个onDelete 函数,但我们从未注入它的实际签名。

如果有人要更改deleteThing 函数;让我们说deleteThing(thingId: number) 而不是deleteThing(thing: IThing)。然后不再工作,但编译器会编译得很好

我觉得使用 typescript 的全部意义在于避免这种情况:deleteThing 的签名已更改,但onDelete 仍会使用旧参数调用它,而不知道它会在运行时失败。

然而,我对打字稿很陌生,所以我可能在这里遗漏了一些重要的东西。

是否有任何最佳实践允许通过角度组件传递函数签名?

感谢阅读!

【问题讨论】:

【参考方案1】:

我想出了一些令我满意的东西:

首先,让我们对ListOfThings组件模板稍作修改:

&lt;thing thing="thing" on-delete="$ctrl.deleteThing($event)"&gt;&lt;/thing&gt;

(而不是deleteThing($event))这样onDeletedeleteThing 具有完全相同的签名。

thing.interface.js中声明一个函数接口:

export interface IDeleteThing 
      (e: $event: thing: IThing): void
    

现在两个控制器都可以导入接口并使用它:

// listOfThings.controller.ts
import IThing, IDeleteThing from './thing.interface.ts'

export default class ListOfThingCtrl 
  private things: Array<IThing>

  public deleteThing: IDeleteThing = ($event) => 
    const i = this.things.map(t => t.id).indexOf($event.thing.id)
    if (i > -1) 
      this.things.splice(i, 1)
    
  


// thing.controller.ts
import IThing, IDeleteThing from './thing.interface.ts'

export default class ThingCtrl 
  private thing: IThing
  private onDelete: IDeleteThing

  public deleteThing (): void 
    this.onDelete($event: thing: this.thing)
  

由于现在在共享模块中定义了签名,因此编译器现在将检测到两个控制器之间的任何不一致 \o/

【讨论】:

以上是关于在 Angular 1.5 中绑定组件函数时如何利用打字稿?的主要内容,如果未能解决你的问题,请参考以下文章

Angular 1.5 组件绑定:检查回调是不是存在

在 Angular 1.5 中使用“单向绑定”(<) 有啥意义?

Angular 1.5+ 组件可选单向绑定

如何在 Angular 1.5 中从父控制器访问组件方法

哪个 Angular 1.5 组件绑定类型更昂贵? '=' 还是'<'?

Angular 1.5 将数据从组件传递到控制器