3 時間で学ぶ TypeScript 入門 ~ 「型」初心者が挑戦|研修コースに参加してみた

今回参加したコースは 3 時間で学ぶ TypeScript 入門 です。
React や Vue.js のフロントエンドフレームワークに続き、モダンなフロントエンド開発ではすっかり定番となった TypeScript です。
以前に C 言語をチョロっと見ただけで、動的型付け言語やマークアップ言語しかやってこなかった私には、初めての静的型付け言語です。 実際、学んでみると中々にお作法の違いがあるなと実感し、コースを受講する前は「フロントエンド書くなら今は TypeScript でしょ」と安易に考えていましたが、ちゃんと用途を分けて使わないといけないと気付けました!
そろそろ TypeScript をやってみるか、と思う方には、従来の JavaScript との違いもわかるコースでしたので、とてもオススメです!
では、どのような内容だったのか、レポートします!
もくじ
コース情報
想定している受講者 | Javascript に関する基礎知識を保有している |
---|---|
受講目標 |
|
講師紹介
プログラミング分野で演習の組み立てが上手な 冨原 祐 さんが登壇されました。

「講師を一生の仕事にする」
React / Express で作る Web アプリケーション開発入門|研修コースに参加してみた
はじめての Go 言語 ( golang ) 入門 研修コースに参加してみた
TypeScript とは
まずは TypeScript の特徴を紹介いただきました。
- Microsoft が開発した OSS の言語
- JavaScript を拡張した「型」がある言語
- TypeScript と JavaScript は相互に変換( トランスパイル )可能
- ただし型を厳密にすると JavaScript → TypeScript ができない
- これを回避するために型を
any
型 (何でも許容する型) がある
- コンパイルする前に IDE が検知するため、結果的に実装は速くなる
- オブジェクト指向言語
JavaScript との違いを簡単な例で比較してみます。
var x = 1;
x = 'こんにちは';
var x: number = 1;
x = 'こんにちは';
変数宣言のあとに number という “型” があることに加えて、実行時には TypeScript の方はエラーがでます。 宣言と異なる型だからですね。
では、 JavaScript から TypeScript にすると開発が楽になるのでしょうか。
- 学習コストが高いので、急に開発効率が上がらない
- ソースコードの保守性では確実にメリットがある
- 大規模開発になれば生産性向上が見込める
“大規模” の定義が難しいところですが、冨原さんから「変数を使いまわして、何が入っているのかわからなくなる規模」とのことでした。 確かに大きいフレームワークやライブラリの中を見たときに、変数とか見えなさすぎてしんどかった記憶が蘇りました。 ちゃんと変数なり、定義があったほうが楽ですね
TypesScript の型
では、 TypeScript にはどんな型があるのでしょうか。
- 型の種類
- number: 数値型 (整数、少数の違いはない)
- string: 文字列
- boolean: 真偽値
- null: null も型
- any: すべての型を許容する
- 配列
型の書き方
続いて、型の書き方について、サンプルコードをもとに見てみましょう。
- 型の宣言
- 変数名の横に書く
var num: number = 3; var name: string = '田中'; var isLock: boolean = false; var sample: any = 'テスト';
- 関数での書き方
// 戻り値がない実行型の場合 function sample(name: string): void { } // 戻り値がある場合 function sample(name: string): number { return 0; }
- constructor() は予約語
class Person {
constructor(private name: string, age: number) {
// 処理
}
purblic run(speed: number): void {
// 処理
}
}
型エイリアス
型の別名を定義する 型エイリアス も使えます。
// 型エイリアスは type を使って定義
type str = string;
var name: str = '田中';
単純に 1 つの型をエイリアスにするだけでなく、複数の値が入った連想配列も名前を付けられます。
type Person = { name: string, age: number };
var p: Person = {
name: '田中',
age: 25
}
こうすると、一時的なクラスのように扱えます。 C 言語の構造体のようですね。 ほかのクラスといっしょに小さいデータ構造を定義する場合や、クラスの中にプライベートクラスを定義するときなどに使えます。
TypeScript 入門演習
では、ここからは座学で学んだことをもとに演習しながら、確かめてみましょう。
インストール
まずはインストールからです。
$ npm install -g typescript
インストールできたか確かめてみます。
$ tsc --version
Version 4.6.2
トランスコンパイルしてみよう
TypeScript <–> JavaScript でトランスコンパイルしてみましょう。
class User {
constructor(public userName: string, public userAddress: string) {
console.log("constructor");
}
getInfo() : string {
return "名前:" + this.userName + " 住所:" + this.userAddress;
}
};
var user = new User('田中', '東京都');
var str = user.getInfo();
console.log(str);
-
コードの解説
- 変数宣言や Setter/Getter 無しで construct するのが常道
- 変数は public にする
このコードをトランスコンパイルします。
$ tsc Sample.ts
生成された JavaScript のソースコードを見てみます。
var User = /** @class */ (function () {
function User(userName, userAddress) {
this.userName = userName;
this.userAddress = userAddress;
console.log("constructor");
}
User.prototype.getInfo = function () {
return "名前:" + this.userName
+ " 住所:" + this.userAddress;
};
return User;
}());
;
var user = new User('田中', '東京都');
var str = user.getInfo();
console.log(str);
prototype を使って継承しているのですね。
それはさておき、これで node.js で実行できるようになったので、動かしてみましょう。
$ node Sample.js
constructor
名前:田中 住所:東京都
ただし、いちいちトランスコンパイルするのは面倒なので、一発でコマンド実行できる ts-node をインストールします。
$ npm install -g ts-node
トランスコンパイルするための設定ファイルが必要なので、それを生成します。 package.json を作るのと同じですね。
$ tsc --init
Created a new tsconfig.json with:
target: es2016
module: commonjs
strict: true
esModuleInterop: true
skipLibCheck: true
forceConsistentCasingInFileNames: true
You can learn more at https://aka.ms/tsconfig.json
では、.ts ファイルを実行してみましょう。
$ ts-node Sample.ts
constructor
名前:田中住所:東京都
できましたね!
ジェネリクス
今度は型を試しながら、 TypeScript はもちろん Java や C# など静的型付け言語ではおなじみの ジェネリクス を使ってみます。
// JavaScript
function writeMessage(mes) {
console.log(mes);
}
writeMessage('テスト');
writeMessage(2);
引数に型がいらない JavaScript では問題が起きないコードも TypeScript ではエラーになります。
// TypeScript
function writeMessage(mes: string) {
console.log(mes);
}
writeMessage('テスト');
writeMessage(2); // エラーになる
そこで登場するのがジェネリクスです。
function writeGenerics<T>(mes: T): void {
console.log(mes);
}
writeGenerics<string>('テスト'); // テスト
writeGenerics<number>(2); // 2
writeGenerics(3); // 3
-
コードの解説
- 型が不明なときは
T
を使う - 利用するときに型を指定して引数に入れる
- 型推論が効くので writeGenerics(3) はエラーにならない
実際のジェネリクスの使い方を見てみます。
class ItemAttr<T>{
name: string;
attr: T;
constructor(name: string, attr: T){
this.name = name;
this.attr = attr;
}
getAttribute(): T {
return this.attr;
}
}
-
コードの解説
- key を受け取って value に複数の型を取るクラス
- getAttribute() の戻り値も複数の型
このクラスを使ってみましょう。
// 文字列を value に取るときは T を string に
var attr1 = new ItemAttr<string>("氏名", "田中");
// number を value に取るときは T を number に
var attr2 = new ItemAttr<number>("年齢", 25);
// 戻り値が string なら T を string にする
var namestr: string = attr1.getAttribute(); // 田中
// 戻り値が number なら T を number にする
var age: number = attr2.getAttribute(); // 25
冨原さんから「持ちたい値ごとに型を指定する」と補足されましたが、確かに変数に何が入るのか、明示的になりますね。
オーバーロード
関数を複数定義して、コンテキストに合わせて使い分けたいときもあります。
function overloads(num: number): number {
return 0;
}
function overloads(str: string): number {
return 0;
}
当然ですが、これはエラーになります。 そこで登場するのが オーバーロード です。
- インターフェイスを 2 つ書く
function overloads(num: number): number; function overloads(str: string): number;
- 本体の処理は 1 つ
- 引数は any にする
function overloads(value: any) { if (typeof value === 'number'){ return 0; } if (typeof value === 'string'){ return 1; } return -1; }
実行してみましょう
console.log("文字の場合:" + overloads("あああ")); // 文字列の場合:0
console.log("数値の場合:" + overloads(0)); // 数値の場合:1
とはいえ、ジェネリクスにせよ、オーバーロードにせよ、素の JavaScript で書くときより考えることが増えます。
TypeScript 実践演習 ~ フロントエンドで TypeScript を使ってみよう
TypeScript の特徴を学んだところで、実際にフロントエンドの開発で使ってみましょう。
環境構築
まずは環境構築からです。
- ビルドツールとして webpack を使う
- 複数のファイルをまとめる
- Web サーバにもなる
では、環境構築を進めましょう。
- typescript と ts-loader をインストール
$ npm install typescript ts-loader
- webpack / webpack-cli (webpack をコマンドラインで使用) / webpack-dev-server (開発用 Web サーバ) をインストール
$ npm install webpack webpack-cli webpack-dev-server
必要なものをインストールできたので、色々な設定ファイルを作成・編集します。
- webpack でビルドして、サーバを動かせるよう package.json にコマンドを追加
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "buiild": "webpack --mode=development", "start": "webpack-dev-server --mode=development" },
- npm run build でビルド、
npm start
でサーバ起動- build は予約語ではないのでコマンド時に run が必要になる
- npm run build でビルド、
- webpack のビルド手順をまとめた設定ファイル webpack.config.js を書く
- ジェネレータが無く手動で書く (げっ 😱)
- 今回は用意いただいたものを使用 (ほっ 😅)
const path = require('path'); module.exports = { // 指定できる値は、ファイル名の文字列や、それを並べた配列やオブジェクト // 下記はオブジェクトとして指定した例 entry: { bundle: './src/app.ts' }, output: { // "__dirname"はこのファイルが存在するディレクトリを表す node.js で定義済みの定数 path: path.join(__dirname,'dist'), filename: '[name].js' // [name]はentryで記述した名前(この例ではbundle)が入る }, // 例えば「 import Foo from './foo' 」と記述すると "foo.ts" という名前のファイルをモジュールとして探す // デフォルトは['.js', '.json'] resolve: { extensions:['.ts', '.js'] }, devServer: { static: path.join(__dirname, 'dist') }, module: { rules: [ { // 拡張子が .ts で終わるファイルに対して TypeScript コンパイラを適用する test:/\.ts$/,loader: 'ts-loader' } ] } }
- entry でビルドを始めるファイルを指定
- output はビルドしたときに生成されるファイルのファイル名と格納場所を指定
- resolve でビルドに使うファイルの拡張子を指定
- devServer に公開するディレクトリを指定
- module でビルドするルールを記述。 今回は .ts ファイルを ts-loader でコンパイルする
- ts ファイルを実行できる tsconfig.json をつくる
$ tsc --init
設定ファイルの準備が完了したので、ブラウザで表示するファイルを準備します。
- HTML ファイルを格納する dist ディレクトリと、ソースコードを格納する src ディレクトリを作成
- 空でよいので src 配下に app.ts を作成
- dist 配下に index.html を作成
- VS Code で html… と入力すれば自動補完で html テンプレートが入力される
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello, TypeScript !!</h1> </body> </html>
- VS Code で html… と入力すれば自動補完で html テンプレートが入力される
では、実行してみましょう!
$ npm start
> type_01@1.0.0 start
> webpack-dev-server --mode=development
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
# 中略
webpack 5.70.0 compiled successfully in 3367 ms
localhost:8080 でも確かめてみましょう。

無事に動きましたね。
簡単な Web アプリケーションを開発
環境構築が完了したところで、簡単な Web アプリケーションを開発してみます。

- 実装する Person クラス
- write() メソッドを持つ
- Person の情報を受け取って、それを HTML の要素にする
- write() メソッドを持つ
Person クラス (person.ts) を定義 → app.ts でインスタンス化 → index.html にデータ表示 とデータを受け渡すよう、作っていきます。
- Person クラスを作り constructor() を書く
- コンストラクタ引数は id / 名前 / 住所
class Person { constructor( private id: number, private personName: string, private personAddress: string ){} }
- write() メソッドを書く
export class Person { constructor( private id: number, private personName: string, private personAddress: string ){} // 引数に null が入る可能性があるので or null を入れる public write(elem : HTMLElement | null): void { // 要素が null なら何もしない if (elem) { // innerHTML で elem の中に要素を入れる elem.innerHTML += '
' + 'ID:' + this.id + ' 名前:' + this.personName + ' 住所:' + this.personAddress + ''; } } } - 環境構築で作った空の app.ts に Person クラスをインスタンス化して index.html に入れる処理を書く
import {Person} from './person'; // 画面から id="content" の要素を取得する。 なお getElementById() は空なら null を返す var elem = document.getElementById('content'); // Person に情報を入れる var person = new Person(1, '田中', '東京都'); var person = new Person(1, '鈴木', '千葉県'); // 情報が入った HTML 要素を作る person.write(elem);
- index.html に content エレメントを追加
<body> <div id="content"></div> <!-- app.ts がビルドされて bundle.js になる --> <script src="bundle.js"></script> </body>
実行してみましょう!

ちなみに app.ts に新しいデータを追加して保存すると、リロードや再ビルドしなくても自動で更新されます。
React + TypeScript で開発してみよう
フロントエンド開発で主流となっている React と TypeScript を混ぜると、どうなるのでしょうか?
素の JavaScript との違いを体験してみましょう。
環境構築
TypeScript で React はトランスコンパイルできないので、これまでと環境構築が変わります。
- create-react-app を使用する
- TypeScript をテンプレートにしたプロジェクトも作成できる
- ただし create-react-app はフロントエンドのみで開発される場合などで使用されることが多い
$ npx create-react-app type_02 --template typescript
- type_02 というディレクトリが生成されるので移動して
npm start

以前にも create-react-app を使いましたが、2 つのコマンドで完了しました!
なお、私は WSL で構築していたため、 Linux での権限がうまく設定されず、何度も泣きながら構築しました … 。
React コンポーネントにおける TypeScript の書き方の違い
では、 React のコンポーネントを作って、 TypeScript と従来の Javascript との違いを体験しましょう。
- src 配下に components ディレクトリを作成
- コンポーネント Hello.tsx を作成
- .tsx は JSX を含んだファイルの場合に使われる拡張子
- コンポーネントは state や property を持つが、どれになるかは不明
- ジェネリクスを使って解消する
// 文字列型の name というプロパティを持つことを宣言 type Props = { name: string; } // プロパティがあるコンポーネントと認識させる export class Hello extends React.Component<Props> { public render() : JSX.Element { return <h1>こんにちは {this.props.name} さん!</h1> } };
- 一番最初にビルドする App.tsx を編集
- Hello を import する
- 表示する箇所に Hello を入れる
import React from 'react'; import logo from './logo.svg'; import './App.css'; import { Hello } from './components/Hello'
<header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <Hello name='田中'></Hello> <p> Edit <code>src/App.tsx</code> and save to reload. </p>
では、実行してみましょう。

やりました!
ただ、素の JavaScript で React を書くときと比べると、コンポーネントの書き方一つとってもジェネリクスを使ったりと手間が増えます。 冒頭、冨原さんが “学習コストが高い” というのは慣れるのに時間がかかる、ということかも知れませんね。
create-react-app を使わない環境構築
先程は create-react-app を使って 2 コマンドで React 環境を構築しましたが、それではそれぞれのライブラリがどんな役割を果たしているのか、わかりません。
ここでは番外編として、 React 環境を一から構築してみましょう。
npm init
で package.json を作成- webpack, webpack-cli, typescript, ts-loader を
npm install
- react, react-dom, @types/react, @types-react-dom を
npm install
- React は TypeScript を使って開発されてない
- そこで TypeScript の型定義を入れるライブラリ (@type~) を追加
- TypeScript のコンパイル設定をするため tsconfig.json を作成
- カスタマイズが必要 (ES (ECMAScript: JavaSCript の規格) のバージョン指定など)
"compilerOptions": { // 中略 "target": "ES5", "lib": ["ES2020", "DOM"], // 中略 "module": "ES2015", }
- ビルド手順をまとめた webpack.config.js を編集
- .tsx のビルドルールやビルドで使用するファイルを指定
module: { rules: [ { test: /\.tsx?$/, use: "ts-loader" } ] }, resolve: { extensions: [".ts", ".tsx", ".js", ".json"] },
- ビルドの起点となる /src/app.tsx を作成
- npm コマンドでビルドできるよう package.json を編集
- scripts パラメータに build のコマンドを指定 (今回は build のみ使用)
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", },
では、ビルドしてみましょう。
$ npm run build
> type_03@1.0.0 build
> webpack
asset main.js 1.21 KiB [emitted] (name: main)
./src/app.tsx 14 bytes [built] [code generated]
webpack 5.70.0 compiled successfully in 2518 ms
無事にビルドが通りました!
このあと Vue.js でも TypeScript を併用した環境構築を行いました。
これから TypeScript の勉強を始める方へのアドバイス
最後に、このコースをもとに TypeScript の学習を進める方へのアドバイスや注意すべきことをお話いただきました。
- TypeScript ならではの基本的な書き方、変数や戻り値の型、ジェネリクス、クラスやコンストラクタなどを覚えよう
- ただしパターンは少ない
- ライブラリには型定義 (.d.ts ファイル) がないものがあるので注意
- 無い場合はライブラリのソースコードを読んで自分で型定義を書く必要がある
ライブラリについては、フロントエンドの開発では小さいライブラリを大量に使ってツールチェインしているので、かなり注意が必要ですね。
この最後のアドバイスをもってコースは修了しました。
まとめ
TypeScript の特徴と型宣言の書き方、ジェネリクスなど特有の書き方を学び、フロントエンドで React も含めた開発を体験しました。
コース内で再三、冨原さんから学習コストが高いこと、用途に合わせて使うこと、この 2 つを繰り返されていました。 確かに書いてみると JavaScript に慣れているフロントエンドエンジニアには手間や考えることが増えるので、規模が大きい、クリティカルなエラーは許されないケースなど、 “型” のメリットが活かせることが採用する前提になりますね。
一方で、すでに大規模だったりクリティカルな場合で TypeScript に移行するには、かなり開発コストが膨らむような印象も受けます。
100万行の大規模なJavaScript製システムをTypeScriptに移行するためにやったこと | CyberAgent Developers Blog
このため、新規開発で MVP など小さく作る場合は JavaScript で進め、マーケットフィットしたタイミングで TypeScript に移行といった判断が必要になるのかも知れません。
「TypeScript どうしようかな」と思っている方には、その特徴が演習を通じて、よくわかる内容でした!
label SEカレッジを詳しく知りたいという方はこちらから !!

IT専門の定額制研修 月額28,000円 ~/ 1社 で IT研修 制度を導入できます。
年間 670 講座をほぼ毎日開催中!!

SEプラスにしかないコンテンツや、研修サービスの運営情報を発信しています。