Edited at

Node.js(TypeScript)を食わず嫌いしてる人にオススメするときに役立ちそうな知見まとめ

もともとは動的なWebサイト開発のために仕方なく(※もちろん人による)書かされていた感のあるJavaScriptですが、ES6以降の進化はめざましく、表現力の高さは他の言語に全く引けを取らないようになりました。

V8エンジンによるパフォーマンスの恩恵も相まって、私はWeb用途以外にもちょっとしたスクリプトを書く時などにも積極的にNode.jsを活用しています。

一方でかつてのJavaScriptのイメージから食わず嫌い的に避けてしまったり、そもそもJSや周辺エコシステムの進化に関心がない人も多く見られます。

そこで今回は「どうすればNode.jsの敷居を低くして、便利さを知ってもらえるか」の観点から役立ちそうな知見をまとめてみました。


動的型付けなのにかなり早い

詳しくは各ベンチマークの結果を見ていただければ分かりますが、Node.jsは動的型付け言語としてはかなり実行速度が早い部類に入り、場合によっては静的型付け言語を上回ることもあります。

Chromeにも搭載されているV8と呼ばれるエンジンが、JITでネイティブコードにコンパイルして実行しています。(※インタプリタではありません)

V8によって様々な最適化が施されており、同じ関数が繰り返し呼ばれたり、オブジェクトの型が安定しているなどすれば、JITによる高速化の恩恵を受けやすくなります。

逆に言えば書き方によっては最適化されずにパフォーマンスが劣化しますが、とりわけ繰り返し同じ関数が呼ばれるような状態ではほとんどのケースで高い動作性能を発揮するはずです。


エディターはVS Code標準でOK

Node.jsを利用するにあたって、エディターはVisual Studio Codeを標準のまま使うのが最も敷居が低く手っ取り早いでしょう。

VSCodeは既に多くのシーンで利用されているほか、動作が軽快で、Node・フロントエンド領域については追加プラグイン無しでもリッチな開発体験が提供されています。

生JSを書いていてもVSCodeがよしなに型を推測してくれるので、厳密に型が欲しいケースでなければTypeScriptを使わなくても、エディタの力で安心して書き進めることができます。

個人的にはJetBrains製品がとても好きなのでWebStormを利用していますが、IntelliJを使っている人は同じ操作感で使えるので、WebStormを使うなり、IntelliJにプラグインを入れるなりして使うのも良いでしょう。


ts-nodeでTypeScriptをサクッと導入する

TypeScriptを導入するにあたり、JavaScriptへのトランスパイルを事前実行する必要があると思っている方も見かけますが、ts-nodeを導入すればトランスパイルは内部で隠蔽してくれます。

ちょっとしたスクリプトどころか、それなりのアプリケーションでもts-nodeで十分開発を進められるので、TypeScriptのトランスパイルの手間を感じる場面は基本的にありません。

https://github.com/TypeStrong/ts-node

以下のnpmコマンドでサクッと導入できます。

$ npm install typescript ts-node -D

ts-nodeを実行するにはpackage.jsonのscriptsを以下のように追加すると良いでしょう。

{

"scripts": {
"ts-node": "ts-node"
}
}

$ npm run ts-node [ファイル名]

scripts内ではプロジェクトレベルの依存ライブラリを実行できるので、グローバルに入れて環境を汚さずに済みます。もちろんTypeScriptもグローバルに入れずとも問題ありません。


Nodeの定義ファイルを追加する

注意点として、Node.jsの標準モジュールを利用するには別途定義ファイルを入れる必要があります。

スクリプトを書く時にはおまじないのように一番最初に実行しておくと良いかもしれません。

$ npm install @types/node -D


TypeScriptの型の柔軟性を知る

TypeScriptを使っていて個人的に最も感動するポイントは、漸進的型付けであるため、型の扱いが非常に柔軟であるところです。慣れてくると静的型付けでも同じことを期待して、できないことが残念に感じることがあります。


Partial

例えばPartialを使えば「型の一部に合致している」という条件を付与できます。

type Article = {

id: number,
title: string,
body: string
};

const processArticle = (content: Partial<Article>) => {
// do something
};

processArticle({id: 1}); // OK!
processArticle({author: 'hoge'}); // NG!


ユニオン型

またユニオン型を使うと「いずれかの型」とみなすことができ、暗黙的に型を確定させると、あたかもその型であるかのように振る舞うことができます。

type Article = {

id: number,
title: string,
body: string
};

type Author = {
name: string,
age: number
}

const processData = (data: Article | Author) => {
data.name; // 型が確定しておらず、nameが存在すると限らないのでNG

if ('name' in data) {
// Author型と自動判定
console.log(data.age);
} else {
// Article型と自動判定
console.log(data.title);
}
};


Omitで一部の型だけ省略&上書き

例えばArticleはidが数値型であることを要求する一方、フォームで新規データを作成する場合はidをnullableにしたいケースの時は、Omitを使うと簡単に要件が実現されます。

type Article = {

id: number,
title: string,
body: string
};

type NewArticle = Omit<Article, 'id'> & {
id: number | null
};

Omitでidのみ省略し、さらにidをnullableの数値で上書しています。これによってベースのTypeを継承せずに済んだり、コードの重複を防いだりすることができます。

ちなみにここで説明したのはTypeScriptの型操作のほんの一部に過ぎません。応用すればするほど、まだ見ぬ深淵の世界が待ち受けているでしょう。


tsconfigにes2019を設定する

JavaScriptの規格であるECMAScriptはバージョンアップを重ねて、新たなメソッドを提供しています。TypeScriptでもECMAScriptのどのバージョンを基準とするかを設定することができるので、この記事時点での最新であるes2019に設定すると良いでしょう。


tsconfig.json

{

"lib": ["es2019"]
}

設定しないと「あれ、なんでこれ使えないんだ?」と混乱する要因になるので、最初はおまじないのようにes2019を追加したほうが良いかもしれません。


アロー関数に慣れる

JavaScriptの記法は随所に特徴的なものがありますが、とりわけアロー関数が初心者にとっては慣れないかもしれません。

ひとまず憶えておくべきなのはreturnを省略できることでしょう。

const add = (x, y) => x + y;

一つの式で完結する場合は、returnが省略されて、式の結果が自動的に返り値となります。このケースで明示的にreturnが書かれることはほぼないので初めは混乱するかもしれません。

またオブジェクトを返す場合はさらに注意が必要です。

const getArticle = () => ({ id: 1, title: 'book title' });

中括弧{}で囲まれたものはオブジェクトリテラルとなりますが、そのまま書くと関数のブレース構文なのか、オブジェクトの中括弧なのかが判別できなくなってしまいます。

そこでオブジェクトの前後に()をかぶせることでオブジェクトを即時returnできるようになります。


ブラウザ用途ならParcel一択で

せっかくならブラウザ用にもNode.jsを使ってみたいと思うかもしれません。

そんな時はParcelを利用するのが断然オススメです。

プロダクションレベルではWebpackで細かな設定が必要になるケースが多いですが、小さく始めるならとにかくParcelに任せてしまいましょう。

Parcelを使えば簡易サーバー立ち上げはもちろん、トランスパイルやホットリロード、スタイルシートの設定などなど諸々全てよしなにやってくれます。

tsconfigに"jsx": "react", "lib": ["dom"]さえ入れていれば、Reactのアプリケーションもたったこれだけで始めることもできます。


index.html

<html>

<body>
<div id="app"></div>
<script src="./index.tsx"></script>
</body>
</html>


index.tsx

import * as React from 'react';

import * as ReactDOM from "react-dom";

const App = () => '<div>App</div>';
ReactDOM.render(<App/>, document.getElementById("app"));


Webpackはフロントエンドを専門的にやっていないと完全に初心者泣かせなので、Parcelで内部を隠蔽してくれると格段に敷居が下がります。

TypeScript、React、Vueなどを始めるのが難しそうと思われている方はぜひ使ってみてください。