typescript可以使用使用元素类型参数的方法扩展Array.prototype吗?

时间:2016-09-05 02:39:29

标签: generics typescript prototype

这是一个非常长的标题来形容一些非常简单的东西。

interface Array<T> {
  sortBy<T, K>(keyFunction: (t: T) => K): T[];
}

export namespace util {
export function sortBy<Element, Key>(array: Element[], keyFunction: (t: Element) => Key ): Element[] {

    var arrayCopy = array.slice();

    var mapped = arrayCopy.map(function(el, i) {
      return { index: i, value: keyFunction(el) };
    });

    mapped.sort(function(a, b) {
      return +(a.value > b.value) || +(a.value === b.value) - 1;
    });

    for (let i = 0; i < array.length; i++) {
        let indexed = mapped[i];
        array[i] = arrayCopy[indexed.index];
    }

    var result = mapped.map(function(el){
      return arrayCopy[el.index];
    });

    return array;

}
}

Array.prototype.sortBy = function(keyFunction)  {return util.sortBy(this, keyFunction)}

这里我将从MDN实现一些示例代码,通过数组键而不是比较函数进行排序,并尝试使用它来修补Array原型(关于这是否是一个好主意的评论)。

但是,当我调用它时,Typescript无法验证keyfunction的正确参数类型,因此需要使用强制转换来防止编译器错误:

it('should sort in-place', () => {
    var list = [{a: 'z', i: 2}, {a: 'x', i: 0}, {a: 'y', i:1}];
    // all good
    list.sortBy(<Function>(obj) => obj.i);
    expect(list.map((obj) => obj.a)
               .join('')
    ).toBe('xyz');
})


it('should sort in-place', () => {
    var list = [{a: 'z', i: 2}, {a: 'x', i: 0}, {a: 'y', i:1}];
    // Error TS2339: Property 'i' does not exist on type '{}'
    list.sortBy((obj) => obj.i);
    expect(list.map((obj) => obj.a)
               .join('')
    ).toBe('xyz');
})

我有什么方法可以改变这个定义吗?有趣的是,调用util.sortBy(array, function)(即作为函数,而不是方法)使类型参数正常工作。

2 个答案:

答案 0 :(得分:3)

您的界面声明排序功能正在创建与T sortBy<T, K>断开连接的新Array T}。应为sortBy<K>并重复使用Array&#39; T

正确宣言

interface Array<T> {
  sortBy<K>(keyFunction: (t: T) => K): T[];
}

var list = [{a: 'z', i: 2}, {a: 'x', i: 0}, {a: 'y', i:1}];

// Okay
list.sortBy((obj) => obj.i);

答案 1 :(得分:0)

我只想澄清实施的工作原理。实现上的类型参数不需要与接口声明匹配,并且可以包括数组类型:

interface Array<T> {
   sortBy<K>(
      keyFunction: (t: T) => K
   ): T[];
}

Array.prototype.sortBy = function <T, K>(
   keyFunction: (t: T) => K
): T[] {
   ...
};

...

const array = [] as Something[];
const sorted = array.sortBy(x => x.SomeProperty);