TypeScriptで用意されている型
- number
- string
- boolean
- any
var i: number;
var i: number = 10;
var i = 10 // 暗黙の型推論
var x; // any型になる
var nums: number[]; // number型の値の配列
- 列挙型
enum Signal {
Red, // 0
Blue = 3,
Yellow, // 4
}
Signal.Blue // 3
Signal['Blue'] // 3
Signal[3] // 'Blue'
// なお、複数の同名の列挙型を宣言した場合にはそれらがマージされる。
// ただし、最初のメンバを省略できるのはどちらかだけである。
関数
function add(a: number, b?: number): number { // bはオプション
if (b){
return a + b;
} else {
return a;
}
}
// bにデフォルトで10を与えたいなら、
function add(a: number, b: number = 10): number {...}
// 式関数で書くなら、
var add = (a: number, b: number): number => a + b;
関数のオーバーロード
TypeScriptでは、関数のオーバーロードは、インターフェイス(signature)と実装部分を分けて書く。
function add(a: number, b: number): number;
function add(a: string, b: string): number;
function add(a: any, b: any): any { // この(any, any)は上書きされるので、(1. 'string')とかだとエラーが出る。
if (typeof a === "string" && typeof b === "string"){
return a + ' ' + b
}
return a + b
}
クラス
class User {
public name: string; // (アクセス修飾子を書かなくても)デフォルトでpublicになる
constructor(name: string) { // functionはいらない
this.name = name;
}
}
// これを、constuctorの引数の箇所でインスタンス変数の初期化ができる
class User {
constructor(public name: string) {
this.name = name;
}
}
フィールドやメソッドをまとめて、そのクラスのメンバー
と呼ぶ。
アクセス修飾子
アクセス修飾子は、public
, protected
, private
の3種類。
以下のように、constructorの引数の変数名の前にアクセス修飾子をつけることによっても、フィールドを設定することができる。(他のメソッドの引数につけることはできない)
class User {
// public name: string; // 不要になった
constructor(public name: string) { // アクセス修飾子のpublicをつけた
this.name = name;
}
}
getterとsetter
getter/setterを定義すると、(privateのfieldであっても)、ClassName.fieldでアクセス/ClassName.field=xで代入することができるようになる。
getter/setterを使う場合のコンパイルは、ECMAScript 5を使い、tsx main.tsx -t ES5
とする。
class User {
constructor(public name: string) { // アクセス修飾子のpublicをつけた
this.name = name;
}
get name(){
return this._name;
}
set name(newValue: string) {
this._name = newValue
}
}
継承とprotected
class AdminUser extends User {
private _age: number;
constructor (_name:string, _age:number) {
super(_name);
this._age = _age;
}
public sayHi(): void {
console.log("my age: ", + this.age);
super.sayHi();
}
}
先述のUserクラスを継承するAdminUserクラスを書いた。これだと、子クラスにから親クラスのprivateフィールドである_nameにアクセスすることができない。
これを可能にするためには、_nameフィールドをprotected(自分のクラス及び、それを継承するクラス内でのみ使えるアクセス修飾子
)にするとよい。変数名も、_nameではなく、nameにしよう。
static member (= static field + static method)
class User {
static count = 0; // static fieldの定義
name: string;
constructor(name: string) {
this.name = name;
User.count++ // static fieldへのアクセス
}
static showDescription(): void { // static methodの定義
console.log("This class is constructed" + User.count + "times");
}
}
User.showDescription(); // static methodの実行
インターフェイス
型の組み合わせを変数として保持するもの。(Javaだと、メソッドの引数の型と返り値の型の組み合わせを定義するものだったな)
interface Result {
a: number;
b: number;
}
インターフェイスは、継承することもできるし、変数自体をオプション指定にすることもできる。
interface SpringResult {
spring: number;
}
interface FallResult {
fall: number;
}
interface FinalResult implements SpringResult, FallResult {
final?: number; // spring, fallに加え、c(optional)を持つ
}
function getTotal(result: FinalResult) {
if (result.final) {
return result.spring + result.fall + result.final;
} else {
return result.spring + result.fall;
}
}
[1]インターフェイスを関数の引数として使用する場合
先述の通りである。
[2]インターフェイスをクラスで実装する場合
そのクラスは、interfaceで定義されたフィールド/メソッドを持っている必要がある。
interface GameUser {
score: number;
showScoreWithMemo(memo:string): void; // methodのsignature
}
class User implements GameUser {
score:number = 0; // ちゃんと実装
constructor(name:string) {
this.name = name;
}
showScoreWithMemo(memo: string): void { // ちゃんと実装した
console.log("score: " + this.score);
}
}
Generics型
[1]関数で使用する場合
function getArray<T>(value: T) : T[] {
return [value, value, value]
}
console.log(getArray<string>("a")); // Tにstringが代入される
// ["a", "a", "a"]
// <string>を省略した場合には型推論によって、Tにstringが代入されるっぽい。
console.log(getArray("a"));
// ["a", "a", "a"]
[2]クラスで使用する場合
class User<T>{...}
// 初期化する際には<T>も書く
u = new User<T>();
// <T>を省略した場合には型推論が使われる
u = new User();
Generics型に制約を与える
Generic型に対して、それが特定のフィールドを持つオブジェクトである
という制約を与えたい場合には、T extends (interface)
としてやれば良い。なお、Tがinterfaceで定義されるプロパティを指定された形でもつ
ことが最低条件になる。前述したように、これは、最低条件であり、これに加えてcというattributeを持っていたりしても構わない。
interface Result {
a: number;
b: number;
}
class MyData<T extends Result> { // Tはa(number)とb(number)というattributeを持つことがmust
constructor(public value: T) {}
getArray(): T[] {
return [this.value.a, this.value.b]
}
}
var number_values = new MyData<Result>({a: 1, b: 2});
console.log(number_values.getArray());
// <Result>を省略した場合、T = Resultになるっぽい
var number_values = new MyData({a: 1, b: 2});
console.log(number_values.getArray());