TypeScript - 弱类型导致索引签名,导致类型检查不佳

时间:2017-10-06 12:21:22

标签: angularjs typescript

使用索引签名比使用AngularJs更令人担忧,但这是一个我认为需要以某种方式解决TypeScript类型的关键问题。

除了TypeScript 2.4的弱类型之外,@ types / angularjs IController开始抱怨弱类型,而修复(此时唯一可能的修复)是添加索引签名,如下所述:

https://github.com/DefinitelyTyped/DefinitelyTyped/issues/17257 https://github.com/DefinitelyTyped/DefinitelyTyped/pull/17303

但是在此更改之前,TypeScript错误将有助于确保当您使用对象中的属性键入IController时,它会(恰当地)抱怨您错过了定义属性,这是使TypeScript成为非常有用的事情之一伟大的语言(至少IMO)。

这是使用简化的AngularJs 1.5组件的直接示例:

let MyComponent = function(): angular.IComponentOptions {
  return {
    bindings: {},
    controller: MyController,
    controllerAs: 'vm',
  }
}

interface IController extends angular.IController {
  x: string;
}

function MyController(this: IController) {
  let vm = this;
  vm.x = "foo"; // OK
  vm.x = 1; // ERROR: As expected due to the definition - great

  // This next line would have complained before this, 
  // now it will let it thru unscathed, same with functions, 
  // arrays, etc. - this is the problem
  vm.y = "bar"; // OK now, ERROR before
}

是否有办法允许AngularJs的类型避免弱类型关注(这是有意义的),同时仍然允许正确检查子类型?

我个人觉得应该尽可能避免索引签名,因为这个问题,并不是避免编译错误的好方法(虽然目前可能是唯一的方法)。

由于

2 个答案:

答案 0 :(得分:0)

您可以使用映射类型解决它,它允许您定义一个强大的接口,但使用Partial映射类型使其属性可选...

// We don't want a weak type... or an index signature...
interface WeakType {
    x?: string;
}

interface StrongType {
    x: string;
}

type PartialStrongType = Partial<StrongType>;

function doSomething(options: PartialStrongType) {
    return options.x || '';
}

doSomething({}); // OK

doSomething({ x: 'str' }); // OK

doSomething({ x: 1 }); // x can't be a number

doSomething({ y: 'str' }); // hey, you typed 'y', did you mean 'x'

答案 1 :(得分:0)

我能提出的唯一解决方案是需要更改本地角度类型定义文件(或者可能是上游推送)。现在,角度中IController的定义看起来像这样:

interface IController {
  $onInit?(): void;
  $doCheck?(): void;
  $onChanges?(onChangesObj: IOnChangesObject): void;
  $onDestroy?(): void;
  $postLink?(): void;
  [s: string]: any;
}

也许应该改为:

interface IControllerWeak {
  $onInit?(): void;
  $doCheck?(): void;
  $onChanges?(onChangesObj: IOnChangesObject): void;
  $onDestroy?(): void;
  $postLink?(): void;
}

interface IController extends IControllerWeak {
  [s: string]: any;
}

对于下游的每个人来说,这应该完全相同,但它现在为您提供IControllerWeak的引用,IController只有IController而没有索引签名。在大多数(所有?)案例中,要求IControllerWeak的内容会接受IControllerWeak,反之亦然。

所以现在你可以使用必需的属性扩展interface IController extends angular.IControllerWeak { x: string; } function MyController(this: IController) { let vm = this; vm.x = "foo"; // OK vm.x = 1; // ERROR vm.y = "bar"; // ERROR as desired } ,并且你有一个非弱(强?)类型,你有所需的保证:

IComponentOptions.controller

MyController很高兴接受IControllerWeak(或let MyComponent = function(): angular.IComponentOptions { return { bindings: {}, controller: MyController, controllerAs: 'vm', } } 子类型的构造函数):

{{1}}

这对你有用吗?