- Published on
TypeScript基礎
- Authors
- Name
- Kikusan
- install
- webpackでのTypeScriptの使用
- 実行
- 構文
- 型
- リテラル型
- テンプレートリテラル型
- 共有型と型ガード
- 演算子
- 配列・連想配列・列挙体・タプル
- 列挙型
- タプル
- 関数
- オブジェクト指向
- 抽象クラス
- インターフェイス
- シグニチャ
- ジェネリクス
- モジュールシステム
公式: https://www.typescriptlang.org/docs/
install
npm install -g typescript
- コンパイルするには
tsc hello.ts
tsc --outFile myApp.js module.ts module2.ts
webpackでのTypeScriptの使用
npm init -y
npm i -D webpack webpack-cli
npm i -D @babel/core @babel/preset-env babel-loader
npm i -D typescript @babel/preset-typescript
tsc --init
- babel.config.js
module.exports = {
presets: [
'@babel/preset-env',
'@babel/preset-typescript'
],
}
- webpack.config.js
const path = require('path');
module.exports = {
mode: process.env.NODE_ENV || 'development',
entry: './src/app.ts', // 読み込みエントリファイル
output: {
filename: 'main.js', // 出力ファイル
path: path.resolve(__dirname, 'dist'), // 自フォルダ
},
resolve: {
extensions: ['.js', '.ts']
},
module: {
rules: [
{
// js/tsを対象
test: /\.(j|t)s$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader', // babel使用でビルド
}
}
]
},
cache: true
};
- package.json
{
"name": "typescript",
"scripts": {
"build": "webpack",
"dev": "webpack --watch",
"lint:ts": "tsc --noEmit"
},
"devDependencies": {
"@babel/core": "^7.17.2",
"@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.16.7",
"babel-loader": "^8.2.3",
"typescript": "^4.5.5",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2"
}
}
./src/app.tsを記載して以下でビルド
npm run lint:ts # コンパイルエラー検知
npm run dev # ライブコンパイル
npm run build # コンパイル
実行
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="dist/main.js"></script>
</body>
</html>
構文
型
let int : number = 0;
// 数値リテラル 0xFF : 16進数, 0o66: 8進数, 0b1011: 2進数
let str : string = '';
console.log(typeof str); // number
let bool : boolean = true;
let sym : symbol = Symbol();
// 基本的にanyは使わないこと
let a : any;
a = 1;
console.log(typeof a); // number
a = 'str'; // any型では型チェックが停止する
console.log(typeof a); // string
let b; // 型/初期値を省略してもany型になる(undefined,nullが初期値でも)
b = 1;
b = 'str';
// tsconfigのnoImplicitAnyオプションが有効だと引数などでanyは使えない
function greeting(name: string) {
return `Hello ${name}!`;
}
console.log(greeting("Taro"));
リテラル型
// タプルや共有型にtype で型エイリアスをつけられる
type MyType = [ string, number, boolean];
let data: MyType = ['abc', 1, false];
// 入れられるものの制限みたいなのもできる
type Season = 'spring' | 'summer' | 'autumn' | 'winter';
function getSeason(s: Season) {
return s.toUpperCase();
}
console.log(getSeason('spring')); // SPRING
// 型注釈はオブジェクト型リテラルも使える
let a2: {
kind: string;
weight: number;
};
let a3: {
kind: string,
weight: number,
};
テンプレートリテラル型
// 文字列を型として設定できる。ここではyyyy-MM-dd以外受け付けなくなる
type DateFormat = `${number}-${number}-${number}`;
const date: DateFormat = '2022-08-30';
共有型と型ガード
// 共有型
let data: string | boolean; // 共有型: |でどれかを指定できる
function guardFunc(value: string | number) {
// プリミティブ型の判定はtypeof オブジェクトはinstanceof
if (typeof value === 'string') {
return value.toUpperCase(); // 型ガード: typeofで型指定することでコンパイルエラーが起きない
} else {
return value.toFixed(1);
}
}
// 引数 is 型名 とすることで型ガードを関数で行える。
function isContains(inf: string | number): inf is string {
return (inf as string).includes("a"); // bool値を返す
}
if (isContains("aaa")) {
console.log("is contain");
} else {
console.log("is not contain");
}
// unknown型はなにでも入れられるが型ガードがないと操作ができない
let data: unknown = 'Hoge';
if (typeof str === 'string') {
console.log(str.trim());
}
演算子
// ?. はjavaでいうoptional.orElse(undefined) nullとundefinedでヒット
let result = hoge?.trim();
// ?? はjavaでいうoption.orElse(設定値)
result = hoge ?? 'x';
配列・連想配列・列挙体・タプル
// 配列
let ary: string[] = ['a', 'b', 'c'];
ary.push('d');
ary.forEach((data) => {
console.log(data); // a // b // c
});
// readonlyキーワードでは読み取りしかできなくなる
const ary2: readonly number[][] = [[1,2]];
// ary2.push([3,4]); readonlyなのでできない
ary2[0].push(3); // 中身に関してはできる。
console.log(ary2[0][2]); // 3
// 連想配列
let obj: {[index: string]: number;} = {
'a': 1,
'b': 2,
}
console.log(obj.a); // 1
console.log(obj['b']); // 2
列挙型
// 列挙
enum Nums {
ZERO,
ONE = 'one', // string か numberを割り当て可能
TWO = 'two'
}
let n: Nums = Nums.ONE;
console.log(Nums.ZERO); // 0
console.log(n); // one
console.log(Nums[0]); // ZERO
タプル
let tuple: [string, number, boolean] = ['aaa', 10.5, false];
tuple.forEach((data) => {
console.log(data); // aaa // 10.5 // false
});
関数
function greeting(name: string): string {
return `Hello ${name}!`;
}
// 戻り値なし
function voi(): void {}
// never ではループや例外で必ず終端に到達しない
function nev(): never {
while(true) {}
}
// 関数リテラルは型推論で決まる。
const func2 = (num1: number, num2: number) => {
return num1 + num2;
}
console.log(func2(1, 2)); // 3
// greeting() // 宣言した引数は必須
// 引数名?で省略可になる
function showTime(time?: Date): string {
if (time === undefined) {
return (new Date()).toLocaleString();
} else {
return time.toLocaleString();
}
}
// 引数にデフォルト値を与えられる
function showTime2(time: Date = new Date()): string {
return time.toLocaleString();
}
// 可変長引数 ...
function sum(...values: number[]) {
let result = 0;
for (let value of values) {
result += value;
}
return result;
}
console.log(sum(1, 2, -3, 10)); // 10
// オーバーロード
// 宣言の直前にシグニチャを記載する(型チェックのため)
function overload(value: number): void;
function overload(value: boolean): void;
function overload(value: any): void {
// anyで受け取り、シグニチャの分だけ実装する
if (typeof value === 'number') {
// numberの場合
} else {
// booleanの場合
}
}
オブジェクト指向
class Animal {
// 静的メンバー
public static LEGS: number = 4;
// public, protected, private がjavaと同じく使える。
private _name!: string; // !は初期化チェック回避
#_age!: number; // #はprivateと同義
// コンストラクター
constructor(name: string, age: number) {
this._name = name;
this.#_age = age;
}
// 静的メソッド
public static getLegs(): number {
return this.LEGS; // staticでもthisが必要
}
// getアクセサ
get age(): number {
return this.#_age;
}
// setアクセサ
set age(age: number) {
this.#_age = age;
}
describe(): string {
return `${this._name}は${this.#_age}歳です。`;
}
// メソッドチェーンの実装
plusAge(value: number): this {
// thisを返すことでメソッドチェーンできるようになる
this.#_age += value;
return this;
}
}
let p = new Animal("dog", 10);
p.age = 10;
console.log(p.age);
console.log(Animal.getLegs()) // 4
// 継承
class Dog extends Animal {
protected kind: string;
// コンストラクターオーバーライド
constructor(name: string, age: number, kind: string) {
super(name, age);
this.kind = kind;
}
// 独自メソッド
bark() {
console.log('bowwow!');
}
// メソッドオーバーライド
describe(): string {
return super.describe() + `${this.kind}という種類です。`;
}
}
// コンストラクター省略 メンバー作成と初期化を同時にできる
class Animal {
constructor(private name: string, private age: number) {}
}
抽象クラスとインターフェイスはjavaと一緒。
javaと異なる点は、構造的部分型: 同じメソッドやメンバーがあれば、型互換性がある
抽象クラス
// 抽象クラス
abstract class Animal {
// 抽象メソッド
abstract sleep(): string;
}
class Dog extends Animal {
// 抽象メソッドは実装を強制される
sleep(): string {
return 'Dog is sleeping';
}
}
インターフェイス
// インターフェイス
interface Animal {
kind: string;
sleep(): string;
}
class Dog implements Animal {
sleep(): string {
return 'Dog is sleeping';
}
}
// インターフェイスは型注釈にも使える
const cat: Animal = {
kind: 'cat',
sleep(): string {
return 'Cat is sleeping';
}
}
シグニチャ
interface Animal {
readonly name: string; // readonlyは読み取り専用プロパティ
age?: number; // ?は省略可能を示す
}
//コールシグニチャ
interface Calc {
(x: number, y:number): number;
}
let add: Calc = function (a: number, b: number): number {
return a + b;
}
// インデックスシグニチャ: 繰り返し利用するデータ型に有効
interface HashMap {
[index: string]: number;
}
let map: HashMap = {
'str1': 1,
'str2': 2,
};
// コンストラクタシグニチャ
interface Animal {
new(name: string): Dog;
}
class Dog {
constructor(private name: string){}
}
ジェネリクス
// <>でジェネリクスが使える。_を入れてるのはjsxだと認識されないため
const toArray = <T, _>(arg1: T, arg2: T): T[] => [arg1, arg2];
console.log(toArray(8, 3)); // [8,3]
モジュールシステム
ES Modulesに準拠。
ただし拡張子は記載しない
探索されるのは、.ts
, .tsx
, .d.ts
, package.jsonのtypesで期待したファイル
, /index.ts
, /index.tsx
, index.d.ts
外部のモジュールはJavaScriptで配布されているものがほとんど。
これをTypeScriptで読み込むための型情報が入っているのが、.d.ts
ファイル。