TypeScript 3 と jQuery で sort() を使う方法

はじめに

今日は TypeScript 3 で jQuery を使用した際に sort() を使う方法を2つご紹介します。

TypeScript
3.7.4
jQuery
3.4.1
目次
  1. そのまま実装したらエラーになった
  2. 手っ取り早い any キャスト
  3. キャストしないで対応
  4. おわりに

1. そのまま実装したらエラーになった

jQuery で sort をするためには下記のようなコードで実装できます。

/sample.html
<ol>
  <li>B</li>
  <li>D</li>
  <li>C</li>
  <li>A</li>
</ol>
<script src="js/main.js"></script>
/js/main.js
$("ol").html(
  $("li").sort(function(a, b) {
    return ($(a).text() > $(b).text()) ? 1 : 0;
  })
);

しかし、これをそのまま TypeScript のコードにしたところ、下記エラーが出てコンパイルができませんでした。

src\main.ts(2,11): error TS2339: Property 'sort' does not exist on type 'JQuery<HTMLElement>'.
src\main.ts(2,25): error TS7006: Parameter 'a' implicitly has an 'any' type.
src\main.ts(2,28): error TS7006: Parameter 'b' implicitly has an 'any' type.

下2行の変数 a, b については型指定がなくて怒られているので「a: HTMLElement」のようにすれば大丈夫でしょう。 問題は JQuery<HTMLElement> 型 に sort() 関数が定義されていないことです。

2. 手っ取り早い any キャスト

一番簡単そうなのは $("li") の箇所を any にキャストする方法です。例えば下記のように実装できます。

/src/main.ts
const $li:any = $('li');
$('ol').html(
  $li.sort((a: HTMLElement, b: HTMLElement): number => {
    return  ($(a).text() > $(b).text()) ? 1 : 0;
  })
);

3. キャストしないで対応

キャストをすれば簡単です。しかし、それでは TypeScript の良さを失っているような気がします。それを避ける方法として下記を考えました。

/src/main.ts
$('li').get().sort((a: HTMLElement, b: HTMLElement): number => {
  return ($(a).text() > $(b).text()) ? 1 : 0;
}).forEach((value) => {
  $('ol').append($(value));
});

処理の内容は、まず $('li').get() で jQuery オブジェクトを配列に変換し、その配列をソートします。次に、ソート後の配列の各値を jQuery オブジェクトとして取得し、append() で並べ替えます。

これでキャストせずに実装できたのですが、最初のコードと比べるとちょっと煩雑で、今度は jQuery の良さが活かされていないように見えます。

4. おわりに

今後 TypeScript の勉強を進めれば、もっとスマートな方法が分かるのかなとも思っています。その際は続報として投稿しようと思います。