TypeScript の型システムの主な特徴については、「なぜ TypeScript なのか」の回で説明したとおりです。

  • TypeScript の型システムは、あなたの JavaScript が TypeScript になるように、オプションで設計されています。

  • TypeScript は Type Error があっても JavaScript の emit をブロックしないので、JS を徐々に TS に更新することができます。

では、まず TypeScript タイプシステムの文法について説明します。 こうすることで、これらのアノテーションをコードですぐに使い始めることができ、その効果を実感することができます。

前述のように、型は :TypeAnnotation 構文を使用してアノテーションされます。 型宣言スペースで利用可能なものはすべて、型アノテーションとして使用できます。

次の例では、変数、関数パラメーター、および関数の戻り値に対する型アノテーションを示しています。

var num: number;
var str: string;
var bool: boolean;
num = 123;
num = 123.456;
num = '123'; // Error
str = '123';
str = 123; // Error
bool = true;
bool = false;
bool = 'false'; // Error

配列

TypeScript は配列のための専用の型構文を提供し、コードの注釈や文書化を容易にする。 この構文は基本的に、有効な型注釈 (例: :boolean) に をポストフィックスするものです。 これにより、通常行うような配列操作を安全に行うことができ、間違った型のメンバを代入してしまうようなエラーから保護されます。

var boolArray: boolean;
boolArray = ;
console.log(boolArray); // true
console.log(boolArray.length); // 2
boolArray = true;
boolArray = ;
boolArray = 'false'; // Error!
boolArray = 'false'; // Error!
boolArray = ; // Error!

Interfaces

Interfaces は、複数の型アノテーションを単一の名前付きアノテーションに合成する TypeScript のコアな方法である。 次の例を見てみましょう。

interface Name {
first: string;
second: string;
}
var name: Name;
name = {
first: 'John',
second: 'Doe'
};
name = { // Error : `second` is missing
first: 'John'
};
name = { // Error : `second` is the wrong type
first: 'John',
second: 1337
};

ここで、first: string + second: string のアノテーションを、個々のメンバーに対して型チェックを行う新しいアノテーション Name に合成しています。

Inline Type Annotation

新しい interface を作成する代わりに、:{ /*Structure*/ } を使用してインラインで好きなものにアノテーションを付けることができる。 前の例では、再びインライン タイプを示しました:

var name: {
first: string;
second: string;
};
name = {
first: 'John',
second: 'Doe'
};
name = { // Error : `second` is missing
first: 'John'
};
name = { // Error : `second` is the wrong type
first: 'John',
second: 1337
};

インライン タイプは、何かに対して 1 回限りのタイプ注釈をすばやく提供するのに適しています。 それは、(潜在的に悪い)型名を考え出す手間を省くことができます。 しかし、同じ型注釈を何度もインラインに置いていることに気づいたら、それをインターフェイス (またはこのセクションで後述する type alias) にリファクタリングすることを検討するのがよいでしょう。 any, null, undefined, voidである。

any

any型はTypeScriptの型システムで特別な位置を占めている。 この型はコンパイラに立ち去るように伝えるための型システムからの逃げ道を提供する。 anyは型システムのあらゆる型と互換性があります。 つまり、どんなものにも代入でき、どんなものにも代入できるのです。

var power: any;
// Takes any and all types
power = '123';
power = 123;
// Is compatible with all types
var num: number;
power = num;
num = power;

JavaScriptのコードをTypeScriptに移植する場合、最初のうちはanyと仲良しになることだろう。 しかし、この友情は、型安全性を確保するのはあなた次第であることを意味するので、あまり深刻に考えないでください。

null と undefined

これらが型システムでどのように扱われるかは、strictNullChecks コンパイラフラグに依存します (このフラグについては後で説明します)。 strictNullCheck:false の場合、nullundefined の JavaScript リテラルは事実上 any 型の何かと同じように型システムで扱われます。 これらのリテラルは他の型に割り当てることができる。 これは以下の例で示されています:

var num: number;
var str: string;
// These literals can be assigned to anything
num = null;
str = undefined;

:void

関数が戻り値の型を持たないことを示すために :void を使用します:

function log(message): void {
console.log(message);
}

Generics

コンピュータサイエンスの多くのアルゴリズムやデータ構造では、実際のオブジェクト型には依存しないものがあります。 しかし、それでも様々な変数間の制約を強制したいものです。 簡単なおもちゃの例としては、項目のリストを受け取り、項目のリストを反転して返す関数があります。

function reverse<T>(items: T): T {
var toreturn = ;
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items);
}
return toreturn;
}
var sample = ;
var reversed = reverse(sample);
console.log(reversed); // 3,2,1
// Safety!
reversed = '1'; // Error!
reversed = ; // Error!
reversed = 1; // Okay
reversed = ; // Okay

ここであなたは基本的に、関数 reverse がある型 T の配列 (items: T) を受け取り(reverse<T> の型パラメータに注目)、型 T の配列を返す(: T に注目)、ということを意味しています。 reverse関数は受け取ったものと同じ型のアイテムを返すので、TypeScriptはreversed変数がnumber型であることも知っており、Type safetyを与えてくれるのである。 同様に、逆関数にstringの配列を渡すと、返される結果もstringの配列となり、以下のような型安全性が得られる:

var strArr = ;
var reversedStrs = reverse(strArr);
reversedStrs = ; // Error!

実はJavaScriptの配列にはすでに.reverse関数があり、TypeScriptはその構造を定義するのに実際にジェネリックスを使っているのである。

interface Array<T> {
reverse(): T;
// ...
}

つまり、以下のように任意の配列に対して.reverseを呼び出すと、型安全性が得られるということです:

var numArr = ;
var reversedNums = numArr.reverse();
reversedNums = ; // Error!

Array<T>インタフェースについては、後ほど「環境宣言」でlib.d.tsについて詳しく説明する予定です。

ユニオン型

JavaScript ではごく一般的に、あるプロパティが複数の型のいずれかになるようにしたい場合があります(例:stringnumber など)。 そこで、ユニオン型(string|numberのような型注釈で|で示される)が便利になります。 一般的な使用例としては、単一のオブジェクトまたはオブジェクトの配列を受け取ることができる関数があります。

function extend<T, U>(first: T, second: U): T & U {
return { ...first, ...second };
}
const x = extend({ a: "hello" }, { b: 42 });
// x now has both `a` and `b`
const a = x.a;
const b = x.b;

Tuple Type

JavaScript にはファーストクラスのタプルのサポートがありません。 人々は一般的に、タプルとして配列を使用します。 これはまさに TypeScript の型システムでサポートされているものです。 タプルは: などのアノテーションを使用できます。 タプルは任意の数のメンバーを持つことができる。

var nameNumber: ;
// Okay
nameNumber = ;
// Error!
nameNumber = ;

TypeScriptの構造改革のサポートと組み合わせると、タプルはその下が配列であるにもかかわらず、かなりファーストクラスのように感じられます:

var nameNumber: ;
nameNumber = ;
var = nameNumber;

Type Alias

TypeScriptには、複数の場所で使用したい型注釈に名前を付けるための便利な構文があります。 エイリアスは type SomeName = someValidTypeAnnotation 構文を使用して作成されます。

type StrOrNum = string|number;
// Usage: just like any other notation
var sample: StrOrNum;
sample = 123;
sample = '123';
// Just checking
sample = true; // Error!

interface とは異なり、文字通り任意の型注釈に型エイリアスを与えることができます (論理和や交差型のようなものに便利です)。

type Text = string | { text: string };
type Coordinates = ;
type Callback = (data: string) => void;

TIP: Type 注釈の階層を持つ必要がある場合、interface を使用します。 これらは implementsextends

で使用できます。

TIP: 単純なオブジェクト構造 (Coordinates など) にセマンティックな名前を付けるために、型の別名を使用します。

まとめ

JavaScript コードのほとんどにアノテーションを付けることができたので、次は TypeScript の Type System で利用できるすべてのパワーの細部に飛び込んでいきましょう。

コメントを残す

メールアドレスが公開されることはありません。