この記事について
この記事はThe TypeScript HandbookのBasic typesをベースに作成したものになります。
TypeScriptの基本的な型の一覧と使い方をまとめてみました。
基本の型
Boolean
最も基本的なデータ型は単純なTrue/False値で、TypeScriptではboolean値と呼ばれています。
let isDone: boolean = false;
Number
JavaScript と同様に、TypeScript のすべての数値は浮動小数点値か BigIntegers です。これらの浮動小数点値はnumberの型を取得し、BigIntegersはbigintの型を取得します。16進数と10進数のリテラルに加えて、TypeScriptはECMAScript 2015で導入された2進数と8進数のリテラルもサポートしています。
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;
String
JavaScriptでウェブページやサーバー用のプログラムを作成する際のもう一つの基本的な部分は、テキストデータを扱うことです。他の言語と同様に、これらのテキストデータ型を参照するために文字列型を使用します。JavaScriptと同様に、TypeScriptでも二重引用符(")や一重引用符(')を使って文字列データを囲んでいます。
let color: string = "blue";
color = 'red';
また、テンプレート文字列を使用することもできます。これらの文字列はbacktick/backquote (`)で囲まれており、埋め込み式は${ expr }の形をしています。
let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.
I'll be ${age + 1} years old next month.`;
これは、このように文章を宣言していることに相当します。
let sentence: string =
"Hello, my name is " +
fullName +
".\n\n" +
"I'll be " +
(age + 1) +
" years old next month.";
Array
TypeScript は JavaScript と同様に、値の配列を扱うことができます。配列の型は2つの方法のうちの1つで書くことができます。1つ目の方法では、要素の型の後に[]をつけて、その要素の型の配列を表します。
let list: number[] = [1, 2, 3];
2つ目の方法では、Arrayという汎用的な配列型を使用します。
let list: Array<number> = [1, 2, 3];
Tuple
タプル型を使用すると、型は既知ですが、同じである必要はありません。例えば、ある値を文字列と数値のペアで表現したい場合などです。
// タプル型の宣言
let x: [string, number];
// 初期化
x = ["hello", 10]; // OK
// 誤った初期化
x = [10, "hello"]; // Error
// Type 'number' is not assignable to type 'string'.
// Type 'string' is not assignable to type 'number'.
既知のインデックスを持つ要素にアクセスすると、正しい型が取得されます。
// OK
console.log(x[0].substring(1));
console.log(x[1].substring(1));
// Property 'substring' does not exist on type 'number'.
既知のインデックスのセット外の要素へのアクセスはエラーで失敗します。
x[3] = "world";
// Tuple type '[string, number]' of length '2' has no element at index '3'.
console.log(x[5].toString());
// Object is possibly 'undefined'.
// Tuple type '[string, number]' of length '2' has no element at index '5'.
Enum
JavaScript の標準的なデータ型のセットに加えて便利なのが enum です。C# のような言語では、enum は数値のセットにより親しみやすい名前を付ける方法です。
enum Color {
Red,
Green,
Blue,
}
let c: Color = Color.Green;
デフォルトでは、列挙型のメンバの番号は 0 から始まります。 これを変更するには、メンバの値を手動で設定します。例えば、先ほどの例では0ではなく1から始めることができます。
enum Color {
Red = 1,
Green,
Blue,
}
let c: Color = Color.Green;
あるいは、列挙されているすべての値を手動で設定することもできます。
enum Color {
Red = 1,
Green = 2,
Blue = 4,
}
let c: Color = Color.Green;
列挙型の便利な機能は、数値から列挙型の中の値の名前に移動することができることです。例えば、値2を持っていたが、上のカラー列挙型の中で何にマッピングされているのかわからなかった場合、対応する名前を調べることができます。
enum Color {
Red = 1,
Green,
Blue,
}
let colorName: string = Color[2];
// 'Green'を表示します。
console.log(colorName); //Green
Unknown
アプリケーションを書いているときにはわからない変数の種類を記述する必要があるかもしれません。これらの値は動的なコンテンツ(例えばユーザからのもの)から来るかもしれませんし、API内の全ての値を意図的に受け入れたいかもしれません。このような場合には、コンパイラや将来の読者に、この変数は何でもあり得ることを伝える型を提供したいので、未知の型を与えます。
let notSure: unknown = 4;
notSure = "maybe a string instead";
// OK, definitely a boolean
notSure = false;
型が不明な変数がある場合、typeofチェック、比較チェック、または後の章で説明するより高度な型ガードを行うことで、より具体的なものに絞り込むことができます。
declare const maybe: unknown;
// 'maybe' は文字列、オブジェクト、ブーリアン、未定義、その他の型になります。
const aNumber: number = maybe;
// Type 'unknown' is not assignable to type 'number'.
if (maybe === true) {
// TypeScript は maybe がブール値であることを知っています。
const aBoolean: boolean = maybe;
// ですから、文字列にはなりません。
const aString: string = maybe;
// Type 'boolean' is not assignable to type 'string'.
}
if (typeof maybe === "string") {
// TypeScript は maybe が文字列であることを知っています。
const aString: string = maybe;
// ということは、booleanであることはできません。
const aBoolean: boolean = maybe;
// Type 'string' is not assignable to type 'boolean'.
}
Any
状況によっては、すべての型情報が利用できるわけではなかったり、その宣言に不適切な努力が必要だったりすることがあります。このような状況は、TypeScriptやサードパーティのライブラリを使わずに書かれたコードの値に対して発生することがあります。このような場合には、型チェックをオプトアウトしたいと思うかもしれません。そのためには、これらの値に any 型のラベルを付けます。
declare function getValue(key: string): any;
// OK、'getValue' の戻り値がチェックされていない
const str: string = getValue("myString");
any型は、既存のJavaScriptを操作するための強力な方法であり、コンパイル中に型チェックを徐々にオプトインしたりオプトアウトしたりすることができます。
unknown とは異なり、any 型の変数では、存在しないプロパティであっても任意のプロパティにアクセスすることができます。これらのプロパティには関数が含まれ、TypeScript はそれらの存在や型をチェックしません。
let looselyTyped: any = 4;
// OK, ifItExists が実行時に存在する可能性があります。
looselyTyped.ifItExists();
// OK, toFixedが存在する(ただしコンパイラはチェックしない)
looselyTyped.toFixed();
let strictlyTyped: unknown = 4;
strictlyTyped.toFixed();
// Object is of type 'unknown'.
anyはあなたのオブジェクトを伝搬し続けます。
let looselyTyped: any = {};
let d = looselyTyped.a.b.c.d;
// ^ = let d: any
結局のところ、便利なものはすべて型の安全性を失う代償を伴うことを覚えておいてください。型の安全性は TypeScript を使う主な動機の一つであり、必要のないときには any を使わないようにするべきです。
Void
void は any の反対のようなもので、型を全く持たないことを意味します。値を返さない関数の戻り値の型としてよく見かけるかもしれません。
function warnUser(): void {
console.log("This is my warning message");
}
void 型の変数を宣言しても、null (--strictNullChecks が指定されていない場合のみ、次のセクションを参照してください) か未定義しか代入できないので、あまり意味がありません。
let unusable: void = undefined;
// `--strictNullChecks` が与えられなければOK
unusable = null;
NullとUndefined
TypeScriptでは、undefinedとnullはそれぞれundefinedとnullという名前の型を持っています。void と同様に、これらの型は単体ではあまり便利ではありません。
// これらの変数に代入できるものはあまりありません!
let u: undefined = undefined;
let n: null = null;
デフォルトでは、null と undefined は他のすべての型のサブタイプです。つまり、number のようなものに null と undefined を代入することができます。
しかし、--strictNullChecks フラグを使用すると、null と undefined は unknown、any、およびそれぞれの型にのみ代入可能です (ただし、undefined は void にも代入可能です)。これにより、多くの一般的なエラーを回避することができます。文字列、または null または undefined のいずれかを渡したい場合は、string | null | undefined という組合わせ型を使用することができます。
Union型については、後の章で詳しく説明します。
Never
never型は、決して発生しない値の型を表します。例えば、関数式や矢印関数式で常に例外を投げるものや、絶対に返さないものは never が返り値の型となります。また、変数は、決して真であることができない任意の型ガードで絞られたときに never 型を取得します。
never型はすべての型のサブタイプであり、代入可能ですが、どの型もneverのサブタイプではなく、代入可能です(never自身を除く)。anyでさえ、 neverに代入可能ではありません。
neverを返す関数の例をいくつか挙げます。
// 関数の戻り値は到達可能な終点を持っていてはいけない
function error(message: string): never {
throw new Error(message);
}
// 推定された戻り値の型は決してありません。
function fail() {
return error("Something failed");
}
// 関数の戻り値は到達可能な終点を持っていてはいけない
function infiniteLoop(): never {
while (true) {}
}
Object
objectは非原始型、つまりnumber、文字string、boolean、bigint、記号、null、未定義でないものを表す型です。
オブジェクト型を使うと、Object.createのようなAPIでより良い表現ができるようになります。例えば
declare function create(o: object | null): void;
// OK
create({ prop: 0 });
create(null);
create(undefined); // undefined は null のサブタイプではないことに注意してください。
// Argument of type 'undefined' is not assignable to parameter of type 'object | null'.
create(42);
// Argument of type '42' is not assignable to parameter of type 'object | null'.
create("string");
// Argument of type '"string"' is not assignable to parameter of type 'object | null'.
create(false);
// Argument of type 'false' is not assignable to parameter of type 'object | null'.
一般的には、これを使う必要はありません。
型のアサーション
ある値について、TypeScript が行うよりも多くのことを知っているという状況に陥ることがあります。通常、これはあるエンティティの型が現在の型よりも特定の型である可能性があることを知っている場合に起こります。
型アサーションは、コンパイラに「信じてくれ、自分が何をしているのか分かっている」と伝えるためのものです。型アサーションは他の言語の型キャストのようなものですが、特別なチェックやデータの再構築は行いません。実行時の影響はなく、コンパイラによって純粋に使用されます。TypeScript は、プログラマであるあなたが必要な特別なチェックを行ったと仮定しています。
型アサーションには2つの形式があります。
一つは as構文 です。
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
もう一つのバージョンはangle-bracket構文です。
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;
2つのサンプルは同等です。どちらか一方を使うかは好みの問題ですが、JSX で TypeScript を使う場合は、as-style アサーションのみが許可されています。
letに関する注意事項
これまでのところ、JavaScriptのvarキーワードの代わりにletキーワードを使ってきたことにお気づきかもしれません。let キーワードは、実は TypeScript が利用できるようにした新しい JavaScript の構文なのです。let と const が var の多くの問題を解決する方法については、変数宣言に関するハンドブックリファレンスを参照してください。
Number, String, Boolean, Symbol, Objectについて
Number, String, Boolean, Symbol, Object の型は、上記で推奨されている小文字のバージョンと同じだと考えたくなるかもしれません。しかし、これらの型は言語プリミティブを参照するものではなく、ほとんどの場合、型として使用すべきではありません。
function reverse(s: String): String {
return s.split("").reverse().join("");
}
reverse("hello world");
代わりに、number、string、boolean、object、symbolの型を使用します。
function reverse(s: string): string {
return s.split("").reverse().join("");
}
reverse("hello world");
まとめ
以上、TypeScriptの基本的な型の一覧とそれらの使い方でした!
TypeScriptを学びたい方にとって、お役に立てれば幸いです!