開発覚書はてな版

個人的な開発関連の備忘録

【TypeScript】Arrayをソートする拡張メソッドの実装 - その1

概要

TypeScript(JavaScript)の標準のsortメソッドが使いにくいので、compare処理を内蔵した拡張メソッドを実装してみたいと思います。

以下の内容で実装したいと思います。

  1. プリミティブ型配列の場合は通常のArray.sort()を実行する。
  2. オブジェクト型配列の場合はプロパティ名を可変長で指定してソートする。

動作環境

  • TypeScript 2.9.x

サンプルソース

export {};

declare global {
  interface Array<T> {
    /**
     * [拡張メソッド]
     * 指定したプロパティを元に昇順にソートします。
     * @param sortKeys 昇順キー
     * @return ソート後の配列
     */
    orderBy<K extends keyof T>(...sortKeys: K[]): T[];
  }
}

Array.prototype.orderBy = function<T, K extends keyof T>(...sortKeys: K[]): T[] {
  const items = this as T[];

  // ソートキーの指定がない場合は、Array.sort()を実行
  if (!Array.isArray(sortKeys) || sortKeys.length === 0)
    return items.sort();
  else {
    return items.sort((a: T, b: T) => compare(a, b, sortKeys));
  }
};

/**
 * ソート判定処理
 * 再帰的にsortKeysを処理して、ソート判定を行います
 */
function compare<T, K extends keyof T>(value1: T, value2: T, sortKeys: K[]): number {
  const key = sortKeys[0];
  const prop1 = value1[key];
  const prop2 = value2[key];

  if (prop1 !== prop2) {
    return (prop1 < prop2) ? -1 : 1;
  } else {
    if (sortKeys.length <= 1)
      return 0;
    else
      return compare(value1, value2, sortKeys.slice(1));
  }
}

K extends keyof TTクラス内のプロパティのみを指定できるようにしています。

実行結果

プリミティブ型配列
const items = [ 3, 4, 2, 1 ];

const actual = items.orderBy();
// output: 1, 2, 3, 4
オブジェクト型配列
const items = [ 
  { id: 2, name: 'bob' }, { id: 3, name: 'alex' }, { id: 1, name: 'char' }, { id: 4, name: 'bob' } 
];

const actual = items.orderBy('name', 'id');
// output: 
// id: 3, name: 'alex'
// id: 2, name: 'bob'
// id: 4, name: 'bob'
// id: 1, name: 'char'

その他

TypeScriptの拡張メソッド関連の記事は以下を参照。

kakkoyakakko2.hatenablog.com

kakkoyakakko2.hatenablog.com