2016年から始めるTypescript


## 動機

個人で書く分にはES6でも十分ですが、チームで開発したり、可読性を上げるにはやはり`型システム`は便利なのかなぁと思います。
最大の動機はReactのソースコードを読んでいて :astonished:  と思ったからです。。
そこでTypescriptの環境構築から実装まで試しました。

## Editor
VSCことVisual Studio Codeを使います

## Typescript

* [公式サイト](http://www.typescriptlang.org/)

```bash:インストール
$ mkdir -p /path/to/develop
$ cd /path/to/develop
$ git init
$ echo -e 'node_modules/\nlib/\n*.log' > .gitignore
$ npm init
$ npm install typescript --save
```

## tsconfig.json

* [解説](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json)
* [property一覧](http://json.schemastore.org/tsconfig)

```json:tsconfig.json
{
  "compileOnSave": true,
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true,
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "typings"
  ]
}
```

targetはデフォルトがes3らしいのでes5にしました。

## tslint

* [公式サイト](https://github.com/palantir/tslint)
* 公式のtslint.jsonを丸パクリした

```bash:インストール
$ npm install tslint --save
```

```json:tslint.json
{
  "rules": {
    ...,
    // セミコロンだけ変えた
    "semicolon": [false],
    ...,
  }
}
```

## Webpack for Typescript

* [公式サイト](http://webpack.github.io/docs/)

```bash:インストール
# typescript, scss, imageのloaderをインストール
$ npm install webpack ts-loader css-loader file-loader style-loader sass-loader url-loader node-sass cross-env rimraf --save-dev
```

```js:webpack.config.js
'use strict'

var webpack = require('webpack');
var path = require('path');
var env = process.env.NODE_ENV;

var config = {
  module: {
    loaders: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        exclude: /node_modules/
      },
      {
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass'],
      },
      {
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader'
      },
    ]
  },
  entry: path.join(__dirname, 'src/app.ts'),
  output: {
    path: path.join(__dirname, 'lib'),
    filename: 'app.js'
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
  ],
  resolve: {
    extensions: ['', '.json', '.ts', '.js'],
    modulesDirectories: ['node_modules', path.join(__dirname, 'src')]
  },
};

if (env === "production") {
  config.plugins.push(new webpack.optimize.UglifyJsPlugin({
    compress: {
      warnings: false
    }
  }));
}

module.exports = config;

```

`npm run`で実行するようにします。

```json:package.json
{
  "name": "typescript-boilerplate",
  "version": "1.0.0",
  "description": "Typescript Boilerplate",
  "main": "lib/app.js",
  "scripts": {
    "clean": "rimraf lib",
    "build": "cross-env NODE_ENV=production webpack",
    "build:dev": "webpack  --display-error-detail",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "rglay",
  "license": "MIT",
  "dependencies": {
    "typescript": "^1.8.7"
  },
  "repository": {
    "git": ""
  },
  "devDependencies": {
    "cross-env": "^1.0.7",
    "css-loader": "^0.23.1",
    "file-loader": "^0.8.5",
    "node-sass": "^3.4.2",
    "sass-loader": "^3.2.0",
    "style-loader": "^0.13.0",
    "ts-loader": "^0.8.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.12.14"
  }
}

```

## ビルドテスト

テストコードは[こちら](http://www.typescriptlang.org/Tutorial)と同じ

```typescript:src/app.ts
class Student {
  fullname: string
  constructor(public firstname: string, public middleinitial: string, public lastname: string) {
    this.fullname = firstname + ' ' + middleinitial + ' ' + lastname
  }  
}

interface Person {
  firstname: string,
  lastname: string
}

function greeter(person: Person) {
  return 'Hello, ' + person.firstname + ' ' + person.lastname
}

const user = new Student('r', 'G.', 'lay')

const div = document.createElement('div')
div.innerHTML = greeter(user)
document.body.appendChild(div)

```

ビルドしてみます。

```bash:ビルド
$ npm run build
```

```html:index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset='UTF8' />
  <title>Typescript boilerplate</title>
</head>

<body>
  <ol>
    <li>One</li>
    <li>Two</li>
  </ol>
</body>

<script src="lib/app.js"></script>
</html>

```

index.htmlを開くと表示されている。

scssも試してみる。

```scss:src/style.scss
@import 'base';

body {
  font: 100% $font-stack;
  color: $primary-color; 
}

```

```scss:src/_base.scss
$primary-color: #333;
$list-color: #00008B;
$font-stack:    Helvetica, sans-serif;

ol {
  margin: 0;
  padding: 0;
}

li {
  @extend ol;
  list-style: none;
  color: $list-color;
  font: 100% $font-stack;
}

```

```typescript:app.ts
// 追加
import 'style.scss'

// あとは同じ
```

```html:index.html
<!-- 同じ -->

```

```bash:ビルド・実行
$ npm run clean && npm run build
```

index.htmlを開けばちゃんとcssが適用されていることがわかる。

## typings
* [公式サイト](https://github.com/typings/typings)
* Typescriptの型情報である`.d.ts`を管理するツールらしい

```bash:インストール
$ npm install typings --global

# ".*tape.*"の正規表現で検索する
$ typings search tage

# "react"の正規表現、つまり完全一致で検索する
$ typings search --name react

$ typings install 
```

試しに[mithril](http://mithril.js.org/)をインストールしてみます。

```bash:mithrilのtypingsインストール
$ typings search --name mithril
Viewing 1 of 1

NAME    SOURCE HOMEPAGE                         DESCRIPTION UPDATED                  VERSIONS
mithril dt     http://lhorie.github.io/mithril/             2015-12-11T18:14:44.000Z 8

$ typings install mithril --ambient --save
```

```typescript:app.ts
/// <reference path="../typings/main.d.ts" />

import * as mithril from "mithril"

```

このように定義すると、`⌘`で型定義に飛べるようになった。
しかしmithrilの場合はかなり古いバージョンなのでこれは使用しないでおきましょう。ハマります。
githubで専用の`.d.ts`が用意されている場合はそれを使うほうがいいのかな？
mithrilは[ここ](http://mithril.js.org/tools.html)にある通り、ダウンロードして使ってね♪ということらしい・・！
便利だけど型情報の鮮度は気にしたほうが良さそうですね。


## まとめ
型はある方が安心ですね。