【问题标题】:How does prototype extend on typescript?原型如何在打字稿上扩展?
【发布时间】:2012-10-07 04:27:35
【问题描述】:

我扩展了函数原型,但 typescript 无法识别它。

Function.prototype.proc = function() {
  var args, target, v;
  var __slice = [].slice;
  args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  target = this;
  while (v = args.shift()) {
    target = target(v);
  }
  return target;
};
// generated by coffee-script

var foo: (number) => (string) => number
  = (a) => (b) => a * b.length;
console.log(foo.proc("first", "second"))

结果:tsc -e

The property 'proc' does not exist on value of type 'Function'

如何扩展这个对象?

【问题讨论】:

    标签: javascript typescript


    【解决方案1】:

    标准 typescript 库中有一个 Function 接口,它声明了 Function 对象的成员。您需要使用您自己的附加组件将 proc 声明为该接口的成员,如下所示:

    interface Function {
        proc(...args: any[]): any;
    }
    

    需要从您打算使用“proc”的任何地方引用此接口。

    【讨论】:

    • 如何用自己的课程做到这一点?
    【解决方案2】:

    像这样:

    declare global {
        interface Function {
            proc() : any;
        }
    }
    

    如果没有“声明全局”,它将不起作用。

    这就是模块扩充在最近的 TypeScript 版本中的工作方式。查看documentation 并向下滚动到Module augmentation 部分。

    【讨论】:

    【解决方案3】:

    静态方法

    declare global { 
      interface NumberConstructor {
        formatCurrency(num: number): string;
      }
    }
    
    export const formatCurrency = (num: number) => {
      if (!num) return '$0';
      return '$' + num.toFixed(0).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
    };
    
    Number.formatCurrency = formatCurrency;
    

    非静态方法

    declare global {
      interface Number {
        formatCurrency: () => string;
      }
    }
    
    Number.prototype.formatCurrency = function() : string {
      return '$' + this.toFixed(0).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
    }
    

    【讨论】:

      【解决方案4】:

      只需添加一点,如果您尝试添加已声明的内容,那么这是类型安全的方式,也可以防止错误的 for in 实现。

      export const augment = <U extends (string|symbol), T extends {[key :string] :any}>(
          type  :new (...args :any[]) => T,
          name  :U,
          value :U extends string ? T[U] : any
      ) => {
          Object.defineProperty(type.prototype, name, {writable:true, enumerable:false, value});
      };
      

      可用于安全地填充。 示例

      //IE doesn't have NodeList.forEach()
      if (!NodeList.prototype.forEach) {
          //this errors, we forgot about index & thisArg!
          const broken = function(this :NodeList, func :(node :Node, list :NodeList) => void) {
              for (const node of this) {
                  func(node, this);
              }
          };
          augment(NodeList, 'forEach', broken);
      
          //better!
          const fixed = function(this :NodeList, func :(node :Node, index :number, list :NodeList) => void, thisArg :any) {
              let index = 0;
              for (const node of this) {
                  func.call(thisArg, node, index++, this);
              }
          };
          augment(NodeList, 'forEach', fixed);
      }
      

      不幸的是,由于limitation in current TS,它无法对您的符号进行类型检查,并且如果字符串 doesn't match any definition 出于某种原因,它不会对您大喊大叫,我会在查看它们是否报告该错误'已经知道了。

      【讨论】:

        【解决方案5】:

        我添加此内容是为了建议不要添加类似示例中所示的原型,因为很多人都会查看此问题。添加如下:

        interface Function {
            proc(...args: any[]): any;
        }
        
        Object.defineProperty(Function.prototype, 'proc', { value: function(arg: any[]) {
            // Your function body
        }});
        

        原因是如果你直接将它添加到原型中,如果该函数的实例被枚举了,它可能会被枚举。 for i in ..。现在这个块可能在你无法控制的代码中(最近发生在我身上),所以最好让你的代码尽可能安全。

        【讨论】:

        • 你没有进行任何类型检查(defineProperty() 不会为你做任何事情),你需要 use a helper like this
        • @Hashbrown 你读过这个问题吗?这里没有类型检查,只是如何扩展现有原型
        • 这是打字稿,字面意思是使用该语言的全部意义。您添加的所有内容都应正确键入。我只是想如果你要警告人们枚举和东西,为什么不保持良好的做法并使用我们刚刚编写的界面(更不用说这些类型的问题被 maaany 人看到,而不仅仅是问题-asker,所以采用最佳实践而不只是回答问题,就像您在这里添加自己的建议一样,不过是一件好事)
        • 我同意你的观点,所有内容都应该输入,但有些输入语法可能有点令人生畏,会让人迷惑,让他们错过重点。
        猜你喜欢
        • 2014-06-11
        • 2020-06-27
        • 1970-01-01
        • 2018-08-30
        • 2021-06-18
        • 2019-09-18
        • 2016-07-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多