!!![このページは移動しました|https://www.typea.info/tips_/index.php/TypeScript] *https://www.typea.info/tips_/index.php/TypeScript !!!TypeScript [Node.js][Angular][Google Cloud Platform] {{amazon B0733113NK}} *https://www.typescriptlang.org/docs/home.html !!準備 !install > npm install -g typescirpt !init ::tsconfig.json の生成 > tsc --init !Visual Studio Code タスク F1 - task run - build tsconfig.json !Playground *動作確認や、どのようなJavascriptに変換されるか確認 *https://www.typescriptlang.org/play/ {{ref_image ts_playground.jpg}} !!!変数・型 !!変数・定数 ,変数宣言,ブロックスコープ,同じスコープでの重複宣言,備考 ,var,認識しない,認める ,let,認識する,認めない ,const,認識する,認めない,再代入不可 !!型 ,型,説明 ,number,数値 ,string,文字列 ,boolean,真偽 ,symbol,シンボル ,any,任意 ,オブジェクト !!文字列リテラル !`バッククオートで囲む *改行もそのまま *${...} ...に変数、式を埋め込み class Program { static main() { let name: string = "Hiroto Yagi"; let age = 46; // 型推論 // age = "Hello"; // 数値型に文字列代入エラー let msg = null; // 初期値未指定、null指定など、any型と類推され型チェックは働かない msg = 100; // noImplicitAny:true とすると、暗黙的 anyは許容しない msg = "Hello"; // テンプレート文字列 console.log(` ${msg} my name is ${name} age ${age} ${new Date()}`); } } Program.main(); ::結果 > node ./src/app.js Hello my name is Hiroto Yagi age 46 toda Tue Nov 07 2017 18:59:23 GMT+0900 (東京 (標準時)) !!型アサーション *キャスト function show(message: string) { console.log(`${message}`); } class TypeAssartion { static main() { // show(10); // ERROR show(10); // OK show(10 as any); // as もOK } } !!コレクション/インターフェース interface StringMap { [index:string]:string; } class Collection { static main() { // 配列 let languages: string[] = ['java','C#','python']; console.log(languages); // 連想配列 let fwMap: {[key:string]:string} = { 'java':'Spring', 'C#':'Asp.net', 'python':'Django' }; console.log(fwMap); // インデクスシグネチャはinterfaceとして事前定義可 let fwMap2: StringMap = { 'java':'Spring', 'C#':'Asp.net', 'python':'Django' }; console.log(fwMap2); } } !!列挙 enum Animal { DOG, CAT, MOUSE, ELEPHANT } enum Fruit { APPLE = "A", ORANGE = "O", PAINAPPLE = "P" } class EnumSample { static main() { let mypet: Animal = Animal.DOG; // デフォルトで0からの数値が割り当てられる console.log(mypet); console.log(Animal[mypet]); let myfavarit: Fruit = Fruit.PAINAPPLE; // 列挙子に値を割り当てることも可能 console.log(myfavarit); } } ::結果 0 DOG P !!タプル let tpl: [string, number, boolean] = ['Yagi', 46, true]; console.log(`name:${tpl[0]} age:${tpl[1]} marriged:${tpl[2]}`); !!共用型 let data: string | boolean; data = 'foo';// OK data = true; // OK // data = 1; // NG let datas: (boolean | number)[] = [true, false, 1, 0]; !!型エイリアス // 主にタプル、共用型に別名を付与。インターフェースでできる場合に使用しないほうがよい type ProfileTuple = [string, number, boolean]; let me = ['yagi', 46, true]; console.log(`name:${me[0]} age:${me[1]} marriged:${me[2]}`); !!文字列リテラル type Season = 'spring' | 'summer' | 'autumn' | 'winter'; class StringLiteralType { printSeason(s: Season) { console.log(s); } static main() { let me = new StringLiteralType(); me.printSeason('summer'); // OK // me.printSeason('hoge'); // NG } } !!!関数 *function命令 *関数リテラル *アロー関数 !!関数、関数リテラル、アロー関数 function squire(x: number, y: number) :number { return x * y; } class FunctionSample{ static main() { // 関数の使用 console.log(squire(8,8)); // 関数リテラル(型推論) let m3 = function(x :number, y: number, z: number): number { return x * y * z; } ; console.log(m3(8,8,8)); // 関数リテラル(型明示) let m2: (x: number, y: number) => number = function(x: number, y: number) { return x * y; }; console.log(m2(9,9)); // アロー関数(ラムダ式) // this は宣言された場所によって変わる let m22 = (x: number, y: number): number => x * y; console.log(m22(5,5)); } } !!引数の省略、デフォルト引数、可変長引数 class FunctionApplySample { static main(){ // TypeScriptでは宣言された引数はすべて必須 // 引数を省略したい場合、仮引数の名前の後ろに ? を付与 let greet = function(message?: string){ message = (message === undefined)?"hello":message; console.log(message); } greet(); greet("good evening"); // 関数のデフォルト値を設定するには、仮引数の後に=デフォルト値 // デフォルト値には、式も利用できる // 明示的に undefined を渡した場合もデフォルト値が利用される let greet2 = function(message: string=`hello ${new Date()}`) { console.log(message); } greet2(); greet2("good night"); greet2(undefined); // 可変長引数 // 仮引数の前に、... とすることで可変長引数となる let sum = function(...nums: number[]):number { let ttl: number = 0; nums.forEach((value,index,array) => ttl += value); return ttl; } console.log(sum(1,2,3,4,5)); } } !!関数のオーバーロード function showMessage(value: number): void; function showMessage(value: boolean): void; function showMessage(value: any): void { let message: string | undefined; if (typeof value === 'number') { message = `${value} is number.`; } if (typeof value === 'boolean') { message = `${value} is boolean`; } console.log(message); } class FunctionApplySample2 { static main(){ console.log("*** 関数応用2 ***"); // 1.シグネチャのみの関数を用意 // 2.具体的な実装を直後に定義 // 3.実装の中で、typeof/instanceof を用いて型を判定し処理を記述 showMessage(123); showMessage(false); showMessage("Hello" as any); } } !!!オブジェクト指向 !!クラス定義 class Person { // メンバー name: string; // デフォルト public private _age: number; // 静的メンバー public static CHEAT_AGES: number = 2; // コンストラクター constructor(name: string, age: number){ this.name = name; this._age = age; } // 以下のコンストラクターでメンバーの宣言と代入を省略できる // アクセス修飾子必須 // constructor(public name: string, private _age: number) { // } // アクセッサー get age(): number { return this._age - Person.CHEAT_AGES; } set age(value: number) { this._age = value; } // メソッド printProfile(){ console.log(`name=${this.name},age=${this.age}`); } } console.log(Person.CHEAT_AGES); let me = new Person('Yagi', 46); //console.log(me.age); // NG me.printProfile(); me.age = 50; me.printProfile(); ::結果 2 name=Yagi,age=44 name=Yagi,age=48 !!名前空間 *namespace ブロックで定義 *exportで外側からアクセス可能なことを明示 *完全修飾名で呼び出す namespace NameA { export class Foo { name() { console.log("NameA.Foo"); } } export function bar(){ console.log("NameA.bar()"); } } let foo = new NameA.Foo(); foo.name(); NameA.bar(); !名前空間のネスト namespace NameB { export namespace NameC { export function bar(){ console.log("NameB.NameC.bar()"); } } } NameB.NameC.bar(); !!継承 class Guiter { constructor(public maker: string, public type: string){} print() { console.log(`${this.type} by ${this.maker}`); } } class Lespaul extends Guiter { constructor(){ super("Gibson","Lespaul"); } } (new Lespaul()).print(); !!抽象クラス // 抽象クラス abstract class Viecle { // 抽象メソッド abstract getEngineDisplacement(): number; printDisplacement() { console.log(`${this.getEngineDisplacement()}`); } } class Premacy extends Viecle { // 抽象メソッドのオーバーライド getEngineDisplacement(): number { return 2000; } // メソッドオーバーライド printDisplacement() { console.log("******"); super.printDisplacement(); console.log("******"); } } (new Premacy()).printDisplacement(); !!インターフェース interface Color { // メソッドはすべて抽象メソッド // abstract 指定は不要 getRGB(): string; } class Red implements Color { getRGB(): string { return "#FF0000"; } } console.log((new Red()).getRGB()); !!構造的部分型(Structual subtyping) class Hoge { constructor(public name: string, public age: number){} } class Spam { constructor(public name: string, public age: number){} } // 継承による明示的な互換性(Nominal subtyping)がなくても構造が一致していれば代入可能 let h: Hoge = new Spam("spam",10); console.log(h); !!型注釈としてのインターフェース *インターフェースを型注釈として利用できる interface Shape { // プロパティシグネチャ name: string; // メソッドシグネチャ draw():void; } let c : Shape = { name:'circle', draw() { console.log(`${this.name}:○`); } }; c.draw(); !オブジェクトリテラル *インターフェースを定義するまでもないが、型情報は明示しておきたい場合 let t : { name: string, sides: number} = {name: 'triangle', sides: 3}; !!型としてのthis class StringBuilder { constructor(protected _value: string){ } toString(): string { return this._value; } wrap(value: string) :string{ return `${value}`; } // 自分自身を返すことで、メソッドチェーンのような記述が可能となる // 派生クラスなど、呼び出し元のクラスに応じ型が変化する append(value: string): this { this._value = this._value + this.wrap(value); return this; } } let buf = new StringBuilder('a'); buf.append('b').append('c').append('d'); console.log(buf.toString()); class CsvBuilder extends StringBuilder { constructor(protected _value: string){ super(_value); } wrap(value: string) { return `,${value}`; } } let csv = new CsvBuilder('a'); csv.append('b').append('c').append('d'); console.log(csv.toString()); ::出力 abcd a,b,c,d !!ジェネリック let numary: Array = [1,2,3,5,8]; !ジェネリック型の定義 *StringBuilder型は、上記で定義参照 class XmlBuilder extends StringBuilder { constructor(protected _value: string){ super(_value); } wrap(value: string) { return `${value}`; } toString(): string { return `${this._value}`; } } // 型引数に制約を付与する場合、extends を使用する。 // 使用しなければ、あらゆる型を渡すことができる class Report { builder: T; getBuilder(): T { return this.builder; } addLine(line: string) { this.getBuilder().append(line); } report() { console.log(this.getBuilder().toString()); } } let rep = new Report(); // ジェネリック型に具体的なインスタンスを紐づけ rep.builder = new XmlBuilder(''); rep.addLine("this is lesson."); rep.addLine("of TypeScript.") rep.report(); ::出力例 this is lesson.of TypeScript. !ジェネリックメソッド function reverse(data: T[]): T[] { let ary: T[] = new Array(); let j=0; for(let i=data.length-1; i>=0; i--) { ary[j++] = data[i]; } return ary; } console.log(reverse([1,2,3,4])); console.log(reverse(["a","b","c","d"])); ::出力例 [ 4, 3, 2, 1 ] [ 'd', 'c', 'b', 'a' ] !!サンプル {{ref app.ts}} !!!Tips !!TypeDoc *https://qiita.com/Mic-U/items/961ce4e0c2a1def1dbd3 *https://qiita.com/ConquestArrow/items/eb4a0dfb13497be4d6a3 !インストール > npm install typedoc -g !作成 > typedoc --out ./docs/ ./src/ --module commonjs