このページは移動しました
TypeScript
[Node.js][Angular][Google Cloud Platform]
準備
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/
変数・型
変数・定数
変数宣言 | ブロックスコープ | 同じスコープでの重複宣言 | 備考 |
---|---|---|---|
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(<any>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<number> = [1,2,3,5,8];
ジェネリック型の定義
- StringBuilder型は、上記で定義参照
class XmlBuilder extends StringBuilder { constructor(protected _value: string){ super(_value); } wrap(value: string) { return `<value>${value}</value>`; } toString(): string { return `<values>${this._value}</values>`; } } // 型引数に制約を付与する場合、extends を使用する。 // 使用しなければ、あらゆる型を渡すことができる class Report<T extends StringBuilder> { builder: T; getBuilder(): T { return this.builder; } addLine(line: string) { this.getBuilder().append(line); } report() { console.log(this.getBuilder().toString()); } } let rep = new Report<XmlBuilder>(); // ジェネリック型に具体的なインスタンスを紐づけ rep.builder = new XmlBuilder(''); rep.addLine("this is lesson."); rep.addLine("of TypeScript.") rep.report();
- 出力例
<values><value>this is lesson.</value><value>of TypeScript.</value></values>
ジェネリックメソッド
function reverse<T>(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<number>([1,2,3,4])); console.log(reverse<string>(["a","b","c","d"]));
- 出力例
[ 4, 3, 2, 1 ] [ 'd', 'c', 'b', 'a' ]
サンプル
app.ts(692)
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
YAGI Hiroto (piroto@a-net.email.ne.jp)
twitter http://twitter.com/pppiroto
Copyright© 矢木 浩人 All Rights Reserved.