0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScriptを学んだ(1) ~型、クラス編~

Posted at

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());

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?