はじめに
こんばんは。 TypeScriptいままでなんとなく他の人のコード見て使ってて、ちゃんとイチから勉強してなかったので、昔買ってたこちらの本見て、ちょっと勉強してみました。
環境構築&初期設定
プロジェクトの作成
$ npm init --yes { "name": "example02", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
TypeScriptのインストール
$ npm install --save-dev typescript added 1 package, and audited 2 packages in 1s found 0 vulnerabilities
TypeScriptのバージョン確認
$ npx tsc --version Version 4.4.4
tsconfig.jsonの作成
$ npx tsc --init message TS6071: Successfully created a tsconfig.json file.
tsconfig.jsonの設定
{ "compilerOptions": { "target": "es5", // コンパイル後のECMAScriptのバージョン "outDir": "dist", // コンパイル後のファイルの設置場所 "rootDir": "src", // Typescriptのディレクトリ起点 "module": "commonjs", // 出力されるJavaScriptがどのようにモジュールを読み込むか "esModuleInterop": true, // commonJS形式で書かれたモジュールをインポートできるようなる "allowJs": true, // jsとtsの共存を許可する "checkJs": true, // jsdocで定義した型の形検査を行う "sourceMap": true, // ソースマップの出力有無 "skipLibCheck": true, // *.d.tsファイルに対する型チェックをスキップする "forceConsistentCasingInFileNames": true, // importのファイルパスん大文字小文字を区別する "strict": true // 厳格チェック }, // コンパイル対象にするディレクトリ位置 "include": [ "src/**/*" ], // コンパイル対象外とするファイル群 "exclude": [ "node_modules", "**/*.test.ts" ] }
型の初歩
プリミティブ型
const bool: boolean = true; const number1: number = 10; const string1: string = "Kojirock"; // or null const bool2: boolean | null = false; const bool3: boolean | null = null;
リテラル型
let str: 'Hello'; str = 'Hello' str = 'aaaa'; => エラー 型 '"aaaa"' を型 '"Hello"' に割り当てることはできません。 # 文字リテラル型とUnion型 type Direction = 'top' | 'right' | 'bottom' | 'left'; function move(direction: Direction) { switch (direction) { case 'top': return '上'; case 'right': return '右'; case 'bottom': return '下'; case 'left': return '左'; } }
配列型
const arr1: number[] = [1, 2, 3]; const arr2: Array<number> = [1, 2, 3];
オブジェクト型
// オブジェクト型 function getAge(user: { age: number }): number { return user.age; } const user1 = { age: 37 }; const user2 = { age: 30, name: 'AAA' }; getAge(user1); => 37 getAge(user2); => 30
Interface
interface User { name: string } function getNmae(user: User): string { return user.name; } const user: User = { name: 'AAA' }; getNmae(user); => 'AAA'
Interfaceの継承
interface Point { x: number; y: number; } interface Point3D extends Point { z: number; } const point: Point3D = { x: 100, y: 200, z: 150, }
オプションプロパティ
undefinedを許可する
interface UserProfile { name: string; nameKana?: string; } const profile: UserProfile = { name: 'kojirock', }
インデックスシグネチャ
動的なプロパティを型にする
interface StringDirectory { [key: string]: string; } const dic: StringDirectory = {}; dic['key1'] = 'value1'; dic['key2'] = 'value2';
列挙型
enum Color { RED = 'red', BLUE = 'blue', YELLOW = 'yellow', } enum LogLevel { VERBOSE, // 0 INFO = 10, // 10 WARNING, // 11 ERROR, // 12 }
関数型
// (x: number,y: number,) => numberまでが定義 // 引数と戻り値の型を指定している const add: (x: number,y: number,) => number = function (x: number, y: number): number { return x + y; } add(100, 200); => 300
クラス
class Point { private x: number; private y: number; public constructor(x: number, y: number) { this.x = x; this.y = y; } public offset(dx: number, dy: number): void { this.x += dx; this.y += dy; } public getX(): number { return this.x; } public getY(): number { return this.y; } } const point = new Point(10, 20); point.offset(40, 40); point.getX(); // => 50 point.getY(); // => 60
Union型
どちらかの型に該当すること anyみたいな使い方にならないように注意
function stringify(value: string | string[]): string { if (Array.isArray(value)) { return value.join(','); } return value; } stringify('Hello'); stringify(['Hello', 'World']);
intersection型
どちらの型にも該当すること
interface View { x: number; y: number; } interface Rectangle { width: number; height: number; } const rectangleView: View & Rectangle = { x: 500, y: 600, width: 24, height: 24 };
型エイリアス
オブジェクト型の型エイリアスはinterfaceと似ている
interfaceの場合、同名で2回定義するとマージされてしまう
type UserId = number; type UserName = string; type Plan = 'Free' | 'Pro' | 'ADVANCE'; type UserProfile = { userId: UserId name: UserName plan: Plan }
ジェネリックス
具体的な型ではなく、「抽象的な」型を扱うことが出来る
本ではあまり理解できなかったけど、こちらのサイトの説明がとてもわかり易かった
test
の引数はstring型だけ、またtest の引数はnumber型だけが許されるようになります。 抽象的な型引数
を関数に与え、実際に利用されるまで型が確定しない関数を作成しています。
function test<T>(arg: T): T { return arg; } test<number>(1); //=> 1 test<string>("文字列"); //=> 文字列
型アサーション
// 型アサーション const value1: any = 'kojirock'; const value2: number = (value1 as string).length
Utility Types
本では一部のみの紹介だったので、 こちら のサイトを参考にさせてもらった
1. すぐに使い道が思いついたもの
Partial<T>
すべてのプロパティをオプショナル(オプションプロパティ)にする
要するに全部 ?
がつくようになる
type UserId = number; type UserName = string; type Plan = 'Free' | 'Pro' | 'ADVANCE'; type UserProfile = { userId: UserId name: UserName plan: Plan } const kojrock: Partial<UserProfile> = { name: 'kojirock' }
Required<T>
type UserId = number; type UserName = string; type Plan = 'Free' | 'Pro' | 'ADVANCE'; type UserProfile = { userId: UserId name: UserName plan: Plan } const kojrock: Required<UserProfile> = { name: 'kojirock', }
Partialの逆で、全部を必須プロパティとなる
Readonly<T>
すべてのプロパティを readonlyにしてくれる
type UserId = number; type UserName = string; type Plan = 'Free' | 'Pro' | 'ADVANCE'; type UserProfile = { userId: UserId name: UserName plan: Plan } const kojrock: Readonly<UserProfile> = { name: 'kojirock', userId: 100, plan: 'Free' } kojrock.name = 'bbb'
Pick<T,K>
T型の中からKで選択したプロパティのみを含んだものを構築して返す
type UserId = number; type UserName = string; type Plan = 'Free' | 'Pro' | 'ADVANCE'; type UserProfile = { userId: UserId name: UserName plan: Plan } type KojirockProfile = Pick<UserProfile, 'userId' | 'name'> const kojirock: KojirockProfile = { userId: 200, name: 'BBB', } const kojirock2: KojirockProfile = { name: 'BBB', }
Omit<T,K>
T型の中からKで選択したプロパティを除いたものを構築して返す
type UserId = number; type UserName = string; type Plan = 'Free' | 'Pro' | 'ADVANCE'; type UserProfile = { userId: UserId name: UserName plan: Plan } type KojirockProfile = Omit<UserProfile, 'userId' | 'name'> const kojirock: KojirockProfile = { plan: 'Free', } const kojirock2: KojirockProfile = { plan: 'Free', name: 'BBB', }
NonNullable<T>
T型からnullとundefinedを取り除いた型を構築して返す
type UserId = NonNullable<number|null>; type UserName = string; type Plan = 'Free' | 'Pro' | 'ADVANCE'; type UserProfile = { userId: UserId name: UserName plan: Plan } const kojirock: UserProfile = { userId: null, name: 'BBB', plan: 'Free' }
2. 使い方はわかったけど、使いみちがイメージできてないもの
Record<K, T>
Exclude<T,U>
Extract<T,U>
Parameters<T>
ConstructorParameters<T>
ReturnType<T>
ThisParameterType
OmitThisParameter
ThisType<T>
終わりに
本では treeコマンドを作るよう流れになってます。
自分も本に沿って作ってみました。
今までなんとなーく他の人のコード見てコピって使ってとかやってて、ジェネリクスとかはぶっちゃけわかってなかったので、おさらいしてよかったです。
まだまだ全然ですが、なんとなく感触をつかめました。
Utility Typesで使い道がわからない所、もうちょい勉強したいと思いました。
あとはガッツリTSでなにか作ってみたいな。
現場からは以上です。