LoginSignup
1
1

More than 5 years have passed since last update.

TypeScriptでJavaのStream#peekがしたい

Last updated at Posted at 2018-10-29

はじめに

Java8から追加されたStream APIのpeekをTypeScriptでする場合の実装例です。
C#の拡張メソッドのようにArrayにpeekというメンバーを追加することで実現していきます。

方法

TypeScript1.8から追加されたGlobal augmentationを使います。
これをすることで、補完機能や型チェックを効かせながらpeekを使用できるようにします。

#global-augmentation Declaration Merging · TypeScript

実装例

ArrayAugmentation.ts
declare global {
  interface Array<T> {
    // JavaのStream#peekを参考に実装
    peek(
      callbackfn: (value: T, index: number, array: T[]) => void,
      thisArg?: any
    ): T[];
  }
}

// プロトタイプ汚染しないように`peek`を拡張。
// コード自体はJavaScriptのときと同じ書き方。
// TypeScriptでもArray.prototype.peek = function...みたいに実装してしまうとプロトタイプ汚染になってしまう。
Object.defineProperties(Array.prototype, {
  peek: {
    value: function(callbackfn) {
      this.forEach(callbackfn);
      return this;
    }
  }
});

// ReadonlyArray<T>やTypedArray(Int8Arrayなど)はArray<T>と継承関係はないため、
// もし、そちらでも使いたい場合は両方ともに実装する必要があります。
// 今回は省略。

// `declare global`を使って拡張する場合は必要となる。
export {};
PeekSample.ts
// peekを実装したモジュールを名前指定せずにimportする。
import "./ArrayAugmentation";

// 以下、peek関数の検証。
// 参考) peekの使い方。
// http://marxsoftware.blogspot.com/2018/06/peeking-inside-java-streams.html

class Person {
  constructor(
    public lastName: string,
    public fistName: string,
    public age: number = 0
  ) {}
}

// ログの出力形式。
const logMessage = function(e: Person): void {
  console.log(`${e.lastName}${e.fistName}${e.age}歳。`);
};

// 赤の他人2人を初期化
const perfectStrangers = [
  new Person("野原", "ひろし", 27),
  new Person("小山", "みさえ", 21)
];

perfectStrangers
  .peek(logMessage)
  // 1年後
  .peek(e => (e.age += 1)) // 正確には結婚時期は未定。
  .peek(e => (e.lastName = "野原"))
  .peek(logMessage)
  // 2年後
  .peek(e => (e.age += 2))
  .concat(new Person("野原", "しんのすけ"))
  .peek(logMessage)
  // 5年後
  .peek(e => (e.age += 5))
  // シロも追加するべきだがPersonではないため省略。
  .concat(new Person("野原", "ひまわり"))
  .forEach(logMessage);

おわりに

peekforEach同様、副作用のある処理を実行することになるので多様は厳禁です。
デバッグ時にログ出力するために使うなど、使用場所は限定しておいた方がいいと思います。

あと、余談ですが、peekと聞くと、java.util.Deque#peekかと思ってしまいます。
peekという英単語が「そっとのぞく、ちらっと見る」という意味になるので、確かにどちらも間違いではないですね。

参考

Declaration Merging · TypeScript
プロトタイプ汚染とループ - latest log
Peeking Inside Java Streams with Stream.peek
Stream (Java SE 10 & JDK 10 )

1
1
0

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
1
1