YYTypeScript#6「JSのプロジェクトにTypeScriptを入れるときの知見」「aspida.jsはAPIクライアントを自動生成するツール」「WebStormとPrettierの相性悪い？」「TypeScript 3.7では何が変わる」「関数型のテストの書き方」「TypeScriptのエディタはVS CodeかIntelliJか」

これは2019年10月25日に開催したTypeScriptイベント[YYTypeScript#6]のイベントレポートです。

[YYTypeScript#6]: https://yyts.connpass.com/event/149440/
[YYTypeScript]: https://yyts.connpass.com/

[YYTypeScript]は一言で「TypeScripterの部室」です。発表者の話を聞く「一方向的な勉強会」とは真逆で、TypeScriptについて、雑に・ゆるく・ワイワイ話しながらTypeScripter同士の交流を深める「双方向的な座談会」の形式になります。集まった人たちで「今日話たいこと」「聞きたいこと」をいくつか挙げていき、それをテーマに雑談していきます。

__今回の配信動画__

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/YYTypeScript?src=hash&amp;ref_src=twsrc%5Etfw">#YYTypeScript</a> 6の収録がアップされました！<a href="https://t.co/w9QMbmNWFS">https://t.co/w9QMbmNWFS</a></p>&mdash; suin❄️AWS &amp; TypeScript (@suin) <a href="https://twitter.com/suin/status/1187704701988433920?ref_src=twsrc%5Etfw">October 25, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


__過去回の配信動画__ → [YouTubeプレイリスト「YYTypeScript」](https://www.youtube.com/playlist?list=PLpOeTEye3Bg4N8f7GSaeqM0p2dcdiZHv_)
__前回__ →  [YYTypeScript#5「TSの好きな機能って何？」「enumは避けるべきか」「TSを選んだ理由を教えて」「業務で犯した型がらみの失敗談」「ソースマップも含めてnpm publishすべき？」「関数で書く派ですか？クラスで書く派ですか？」 - Qiita](https://qiita.com/suin/items/68ee0e6c78ac4423c7f1)

## 雑談


### JavaScriptのプロジェクトにTypeScriptを入れるときの知見を聞きたい (えあんぬ)

* allowJSの知見など知りたい。
* 1,900ファイルぐらいあるけっこうでかいプロジェクト
    * 1900ファイルあるプロジェクトでJSで書くのもしんどそう。。
* ts化して型安全にしたい
* ts化したらエラーが多すぎてつらい

* `noImplicitAny: false`をセットする
    * https://basarat.gitbooks.io/typescript/docs/options/noImplicitAny.html
    * https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
* `allowJS: true`?
* `// @ts-ignore` とコードに書くと、次の行のコンパイラチェックを抑制できる
    * ファイル単位での記述になるので、どうしてもやむを得ない時に、ピンポイントで使える
* そんなにファイル数がないプロジェクトで
    * tsconfigで設定をかなりゆるめにして、1ファイルずつTSに移行した
* noImplicitAnyはできればやりたくない
    * 既存コード用のtsconfigと、新規コード用のtsconfigをわけるとか？
        * パッケージルートの `tsconfig.json` を `root: true` にして、ディレクトリ内部でextendsできます、たしか
* [Migrating from JavaScript · TypeScript](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html)
* tslintで型アノテーションを強制する
    * CIで型アノテーションがなければ落とす
    * [commitlint](https://github.com/conventional-changelog/commitlint)で、lintで失敗したらコミットさせない、という手もあるかも
        * commitlintいいですよね

### aspida.jsについて聞く (ふぃろまぎ)

- [aspida.js](https://github.com/aspidajs/aspida) (アスピーダ JS)
- 型定義を記述しておけば、静的に型付けされたAPIクライアントの実行コードを自動生成してくれるツールです。
- 型定義ファイルだけでなく、実際に動作するtypescriptコードが生成されます。
- スキーマファイルってどんな？
    - TypeScriptで`interface`を書いていく。
- 興味ある人で開発に参加してくれる方募集中だそうです。
    - ASTとかの知見が有る方は、特に歓迎したいそうです
- スキーマ定義があれば、サーバサイドも自動生成できそう。
- APIクライアントを自分で作ろうとすると、ラッパーを書く必要があるが、aspida.jsはそれをやってくれる
- TypeScriptの`interface`でIDLが書けたらいいなと思っていた。
    - aspidaとか、↓こういうのを待ってた
    - [AWSが公開したインターフェイス定義言語(IDL)Smithyのドキュメントを通し読みしてみた ｜ DevelopersIO](https://dev.classmethod.jp/server-side/smihty-document-reading/)

### Webstormとprettierの相性悪い？ (やました ﾘﾓｰﾄ)

Webstormを使っているんですが、formatをsave時に使いたくsuinさんの記事をQiitaで見つけ設定しました。でも、prettierが激遅ぷんぷん丸で困ってます

* [WebStormで自動保存時にPrettierを実行するようにしたら、キレイなコーディングがとても捗る。 - Qiita](https://qiita.com/suin/items/7953a1460e9721bab83d)

...

* たしかにWebStormは保存してから整形されるまでワンテンポあるかんじで、VS Codeを使っていた。
* 保存するとprettierが走ると思うのですが、その間にコードに手を加えると、編集が消えたりするんです
    * VS Codeでは発生しないんですか？
* commitするときに整形しては？
    * [git commitしたときにTypeScriptコードを自動修正する方法(tslint, prettier, lint-staged使用) - Qiita](https://qiita.com/suin/items/ed6739dc1afb125c9b35)
* 解決しないのでsuinの宿題とします。

### TypeScript 3.7では何が変わっているのか、どんな機能が増えているのか (れおりん)

https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc/

- Optional Chaining  `?.`
    - Rubyで似たようなやつがある
        - https://christiantietze.de/posts/2015/11/ruby-safe-navigation/
    - むかしは `foo && foo.bar && foo.bar.buz` ってやってた
    - [tc39/proposal-optional-chaining](https://github.com/tc39/proposal-optional-chaining)
    - `_.get(foo, 'bar.buz')` も有ったけど、型が死ぬ
        - https://www.npmjs.com/package/ts-get-safe
            - どんな型定義になってるか気になる
                - 型定義はっときますね↓

```typescript
function getSafe<TObject, P0 extends keyof TObject, A1 extends GSArrEl<P0, TObject>, P2 extends keyof A1, P3 extends keyof A1[P2], A4 extends GSArrEl<P3, A1[P2]>>(obj: TObject, p0: P0, a1: number, p2: P2, p3: P3, a4: number): A4;
```


- Nullish Coalescing `？？` 
    - `||` と何がちがう？
        - `||`は`0`とか`''`でも、右辺が評価される
        - `null`と`undefined`のときだけ。
- Assertion Functions
    * `type predicate` の強い版？

```typescript
function assertString(value: unknown): asserts value is string {
    if (typeof value !== 'string') {
        throw new Error('...')
    }
}
    
assertString(value) //=> exceptionが発生しうる

value.toUpperCase() // コンパイルが通る (valueがstringだとわかっているので)
```

* コンパイルしてもチェック処理は残る。
* チェック内容がバグってると、コンパイラに間違った情報が伝わるところは注意
    - [TypeScript 3.7の`asserts x is T`型はどのように危険なのか](https://qiita.com/uhyo/items/b8d2ea6fbf6214fc4194)より
- Better Support for never-Returning Functions
- Recursive Type Aliases

- 新機能はどうやって決まるの？
    - ECMAScript由来はTC39
    - TypeScript固有のやつはGitHub issueでディスカッション？
    - assertion function は↓のPR起点？
        - [Assertions in control flow analysis by ahejlsberg · Pull Request #32695 · microsoft/TypeScript](https://github.com/microsoft/TypeScript/pull/32695)
    - Design Meetingというのやってる？
        - https://github.com/microsoft/TypeScript/issues/34576 とか
    - どうやって決めているのか分からないので宿題。

https://github.com/microsoft/TypeScript/issues/33352

* 3.7正式版のリリース予定は11月5日
    * 4時間前にRCが出てるので、概ねスケジュール通り
    * [TypeScript 3.7 Iteration Plan · Issue #33352 · microsoft/TypeScript](https://github.com/microsoft/TypeScript/issues/33352)
* 今後入る予定のESのprivateが気になる
    * [Private named instance fields by mheiber · Pull Request #30829 · microsoft/TypeScript](https://github.com/Microsoft/TypeScript/pull/30829)
    * どっちで書くかでチーム内で宗教論争が起きそう
        * ECMAにしたがったほうがよさげ

### 関数型で書いているときのテストの仕方について (えあんぬ)

* 手続き型と関数型はどうちがうの？
    * 手続き型は、どうやって処理するかを書いていく
    * 関数型は、より宣言的で、関数と関数を組み合わせて作っていくかんじ
        * 関数合成という考え方がある
        * 関数型プログラミングは、関数が第一級市民
    * 元々JavaScriptの作者が、関数型言語作りたかった人らしいから、JSは最初から関数型っぽい言語設計になってるっぽいですね
    * 参照透過性
        * 引数が同じだったら、何度やっても同じ結果が得られる
* functionだけexportすることがあるが、functionが依存するfunctionをモックにするのかどうか
    * `require`に噛んで依存先をモックにするライブラリがあるけど、
        * ちょっとツール依存な気がする
    * 外部にexportする目的には、interface or type を TS で書いて、実装はそれぞれexportしてテストはそれをimportしてテストでいいと思う
    * ports and adapters デザインパターン（ヘキサゴナルアーキテクチャ）とか、インターフェース分離とか、DIP（依存性逆流）とか使うと、外に見せるものを限定しつつ、関数を全部テストするみたいなこともしやすいですね
    * 引数に関数を持つものをテストするときは、jest.fn() でモック作って雑にテストすれば大体いいような気がする
* 関数が依存する関数で、取り替えたい部分はカリー化するとか、引数で渡すとかするといいかも。
* DBを参照したり副作用をもっている関数は、引数で渡すといいと思う
    * 副作用がなければくっついたままテストしてもいいと思う
* 関数とクラスの使い分けに悩んでる
    * 依存物をもたせるならクラスでもいいのでは
* カリー化って？
    * オブジェクト指向のビルダーパータンみたいに、段階的に関数を組み立てていける

```typescript
const add = (v1: int) => (v2: int) => (v3: int) => v1 + v2 + v3

add(1)(2)(3) // => 6

const threePlus = add(1)(2)

threePlus(4) // => 7
threePlus(10) // => 13
```

カリー化とは違うけど、こういうファクトリーというか、段階的に組み立てる書き方は便利な気がしてる:

```typescript
export interface HogePort {
  read(name: string) => Promise<string>
}

export const createHoge = (context: string): HogePort => {
  const read: HogePort['read'] = async (name) => {
    // ... なんかすごいしょり
    return `${name} ${context}`
  }

  return { read }
}

// カリー化とは違うけど、こういうファクトリーというか、段階的に組み立てる書き方は便利な気がしてる


```

```typescript
const createCommandRunner = (conf: Config) => (command: Command) => command.run(conf)

// テスト時のコード
const command = new HogeCommand()
const test = createCommandRunner(testConf)
test.run(command)

// 本番環境のコード
const prod = createCommandRunner(prodConf)
prod.run(command)

```


### クラスの設計について (かきうち)

メールを送るクラス
使う側からBodyを渡す
結果を受け取りたい

・・・

メールとメールを送るクラスを分けるといいかも。

```typescript
const email = { subject: '...', body: '...' }
emailSender.send(email)
```

中途半端なメールを作るなら、それこそBuilderパターンとか、カリー化がいいかも。

```typescript
const createMail = (subject: string) =>
                   (sender: string) =>
                   (body: string) =>
                   (receiver: string) => new Mail(subject, receiver, sender, body)

const sendTo = createMail('hoge')('example@gmail.com')('fuga')

const mailList = users.map(user => sendTo(user.mail))
```

```typescript
interface Mail {
  subject: string
  sender: string
  // ...
}

export function createMailSender(mail: Partial<Mail>) {
  // 全部そろってたら、完成版MailSenderを返す
  // そろってなかったら、Builderを返す
  // とか……
  // - conditional typeとか使えたら夢が広がりそう
}

```

* PHPですが、参考までに: [PHP: Builderパターンの実装手順 #1【基礎実装】](https://qiita.com/suin/items/d8d4dc019d3beb428249)

### TypeScriptのエディタはVS CodeかIntelliJか (れおりん)

何がいいのか、どういう違いがあるのか？

* VS Code使ってる勢: 3
* WebStorm勢: 2
* IntelliJ勢: 3

・・・

* WebStormだとprettier重い
* VSCode は無料で誰でも使えるから、環境統一に便利だと思ってたり
* IntelliJ全員買えるくらいだといいんですけど、なかなかそうはいかなですもんね
* あと、個人的な偏見かもしれないけど、設定を全くしてない状態では、IntelliJ よりも、VSCode が使いやすい気がする
* VS Codeは起動が速いので、TSしか触らないときはVS Code
* VS Codeは Live Shareのプラグインが良く出来てて、ペアプロするならこれになっちゃいました
* JavaとかScalaとかやってるチームや人は、慣れてるIntelliJ でいいような気もする


## 参加してよかったこと(参加者の感想)

* クラスや関数をどう作るかについての議論が楽しかった + 自分の感覚を言語化することができて良かったです
* aspida.js の存在を知れたこと
* カリー化の説明聞けたこと
* カリー化を知らなかった。便利良さそうだから使ってみよう！！
* プログラム好きな人が集まってる雰囲気を感じられたこと
* 1900ファイルあるJavaScriptのプロジェクトにTypeScriptを入れる話は生々しくて面白かった

## YYTypeScriptは毎週やってます

YYTypeScriptについてワイワイ話したい方は、[YYTypeScriptのイベント情報](https://yyts.connpass.com/)をチェックしてみて下さい。

以上、YYTypeScriptのレポートでした。次回もワイワイやっていきたいと思います！ では、また来週！