LoginSignup
2
2

More than 3 years have passed since last update.

[Tips] Typescript With MetaProgramming (Nativeをちょっと拡張しよ)

Last updated at Posted at 2019-07-04

背景

Native型の拡張として 有名な lodash を使ってきたのだけど、
処理が重たいのでやめましょ、というコメントをもらいました。たしかに重たい。 lodash の実装は メソッドチェインにしづらい ので、シーケンシャルに処理を記述できないのが、前々からうーんとなっていた。

lodash でもメソッドチェインはできる点、「lodashが重たい」という点について、コメントをいただきました。確かに lodash でも書きかたでカバーできる可能性がありそうです。

実装

例として、Array型 自体をちょっと拡張してしまおう。

公式にもドキュメントがあります。Declaration-merging という手法を使います。
https://www.typescriptlang.org/docs/handbook/declaration-merging.html

以下は重複を取り除くuniqというメソッドを追加する例です。

array.extensions.ts

export {}

declare global {
    interface Array<T> {
        uniq<T> (comparer: (value1: T, valu2: T) => boolean): T[];
        contains<T> (value: T): boolean;
    }
}

/* eslint no-extend-native: ["error", { "exceptions": ["Array"] }] */
Array.prototype.uniq = function<T> (comparer: (value1: T, valu2: T) => boolean): T[] {
    return this.filter((value1, index1, array1): boolean => {
        const index2 = array1.findIndex((value2): boolean => comparer(value1, value2))
        return (index1 === index2)
    })
}

使うところ

import './array.extensions'

['aaa','bbb','ccc','bbb','ccc']
.filter(elem => elem === 'ccc')
.uniq((v1,v2) => (v1 === v2))

objectの配列でも
[{ID:'aaa'}, {ID:'bbb'},{ID:'ccc'},{ID:'bbb'},{ID:'ccc'}]
.filter(elem => elem.ID === 'ccc')
.uniq((v1,v2) => (v1.ID === v2.ID))

補足

eslint が効いている場合は、no-extend-native がデフォルト有効なので、OFFにしておきます。
無下に拡張すると、もともとのメソッドを上書きしてしまうので、よく検討した上で都度OFFにするコメントを記載しておくのがベターです。

Native型の拡張は、名前を侵食するリスクと隣合わせではありますが、うまく使えると余計なクラス、Interfaceを定義しなくて済むので、頭の片隅においてて損はないと思います。

2
2
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2