【问题标题】:Prohibited attributes in a Typescript InterfaceTypescript 界面中的禁止属性
【发布时间】:2015-04-28 17:34:53
【问题描述】:

我要创建一个 TypeScript 接口,它不仅要求存在特定的属性,而且还禁止不属于定义的属性。这是一个例子:

  export interface IComponentDirective {
    scope : any;
    templateUrl : string;
  };

  var ddo : IComponentDirective = {
    scope: {
      dt: '='
    },
    templateUrl: 'directives.datepicker',
    controller: function() {
      console.log('hello world');
    }
  };

即使controller 没有在接口中定义,ddo 赋值也不会引发错误。做一些研究,这看起来可能是设计的:

请注意,我们的对象实际上有比这更多的属性,但是 编译器仅检查是否至少存在所需的 并匹配所需的类型。

http://www.typescriptlang.org/Handbook#interfaces

但是请注意,在我将 ddo 声明为 IComponentDirective 之后,如果我尝试类似的操作:

ddo.transclude = false;

编译器会抱怨:

2339 类型上不存在属性“transclude” 'IComponentDirective'。

有没有办法强制执行更严格的合同?

【问题讨论】:

    标签: interface typescript typescript1.4


    【解决方案1】:

    简而言之(但取决于您对“更严格”的定义)您不能限制超出此范围的内容。

    界面是一个合同,上面写着“如果这些成员不存在,你就不是其中之一”。如果您的对象碰巧有其他成员,那很好;当您使用界面时,它们对您是不可见的。

    例如(根据您的代码),当您键入ddo. 时,它只会建议接口上的成员,因为您已经告诉编译器使用接口类型。

    您不能使用接口来防止定义一个成员。我想不出任何语言可以做到这一点。例如,在 C# 中,您可以实现比接口要求的更多,但是当您使用接口类型时,其他成员不可用。

    动态添加属性

    ddo.tranclude = false; 为什么会生成警告的问题有点不同。这与接口无关 - 没有接口时会这样做:

      var ddo = {
        scope: {
          dt: '='
        },
        templateUrl: 'directives.datepicker',
        controller: function() {
          console.log('hello world');
        }
      };
    
      ddo.transclude = false; // Nope
    

    原因是……这就是 TypeScript 的意义所在!它警告您,您可能输入了错误的transclude。也许您的意思是templateUrl确实存在。如果 TypeScript 没有警告你这类问题,它会让你在代码中引入印刷错误。

    因此,TypeScript 将为您创建的任何对象生成一个类型,然后强制执行该结构,除非您另有说明。

    如果您希望“有时成为transclude 成员”,您可以做到这一点:

    interface SometimesTransclude {
        scope: { dt: string};
        templateUrl: string;
        controller: () => void;
        transclude?: boolean;
    }
    
      var ddo: SometimesTransclude = {
        scope: {
          dt: '='
        },
        templateUrl: 'directives.datepicker',
        controller: function() {
          console.log('hello world');
        }
      };
    
      ddo.transclude = false;
    

    或者您可以直接跳过编译器(风险自负),使用:

    ddo['transclude'] = false;
    

    【讨论】:

    • 感谢您的快速回复!这在接口的经典意义上是有道理的,但是为什么当你做ddo.transclude = false; 时它会抛出?
    • 我已经添加了一个关于此的部分 - 因为它与接口无关。
    • 嗯,我理解选项参数,但如果它要警告我transclude,它不应该警告我控制器吗?我觉得要么它应该像一个经典接口一样工作,要么它应该警告未知属性,但它似乎是不一致的。另外,我不知道dancing past the compiler - 这有点吓人。
    • 这是有趣的区别。 TypeScript 是结构化类型的,并且会在您创建变量时为您生成一个类型 - 并强制执行该生成的类型。这意味着您可以在第一次创建 ddo 时将任何您喜欢的东西放在它上面 - 但之后,会检查类型。 (我在我的书中详细介绍了这一点......提示提示;))
    • 谢谢史蒂夫。我不是这个工作原理的忠实粉丝,但我认为你的描述值得勾选。 :)
    猜你喜欢
    • 2018-04-10
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2021-03-26
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多