【翻訳】TypeScript Basic Types + α

# TypeScriptの型について

[TypeScript Basic Types](https://www.typescriptlang.org/docs/handbook/basic-types.html)

こちらのドキュメントをGoogle翻訳よりもわかりやすく翻訳してみました。
本家にはない説明も加えてありますのでよく読み、用法・用量お守りください。

# 基本的な型

- <a href="#introduction">はじめに</a>
- <a href="#boolean">Boolean</a>
- <a href="#number">Number</a>
- <a href="#bigint">Bigint</a>
- <a href="#string">String</a>
- <a href="#array">Array</a>
- <a href="#symbol">Symbol</a>
- <a href="#tuple">Tuple</a>
- <a href="#enum">Enum</a>
- <a href="#any">Any</a>
- <a href="#unknown">Unknown</a>
- <a href="#void">Void</a>
- <a href="#nullAndUndefined">Null and Undefined</a>
- <a href="#never">Never</a>
- <a href="#object">Object</a>
- <a href="#typeAssertions">型注釈</a>
- <a href="#let"><span style="color: orange">let</span>に関するメモ</a>

<a id="introduction"></a>

## はじめに
使いやすいプログラムの為に、私たちは「数値」「文字列」「構造」「ブール値」などのもっとも単純なデータ単位を操作できる必要があります。
TypeScriptでは、JavaScriptで期待されるものとほぼ同じ型をサポートしています。
便利な列挙型を利用して、操作を手助けします。  
以下、サンプルコードが記述されていますが、TypeScriptの型指定ではJavaScriptとは違い基本的に**小文字**で始まることに注意してください。
大文字で始まる型宣言は、JavaScriptコードで適切に使用されることはほとんどない非プリミティブのオブジェクトとして参照されてしまうので使用しないでください。

<a id="boolean"></a>

## Boolean
最も基本的なデータ型は、単純な`true/false`値で、JavaScriptおよびTypeScriptで`boolean`を使用します。

```ts
let isDone: boolean = false;
```

## Number
JavaScriptと同様に、TypeScriptの数値はすべて浮動小数点数です。これらの浮動小数点数は`number`を使用します。
16進数(hexadecimal)と10進数(decimal)に加えて、TypeScriptではECMAScript 2015で導入された2進数(binary)と8進数(octal)もサポートしています。

```ts
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
```


<a id="bigint"></a>

## Bigint

`bigint`型は、ECMAScriptの新しい規格として定義されています。(upcoming proposal)
`number`型が扱える正確な数値として52bit(`2^53-1`bit)ですが、それ以上の値を扱う際に使用する型です。
`number`型では最大値を超えると表示上 `Number.MAX_SAFE_INTEGER = 9007199254740991` になりますが、
`bigint`型を使用するとJavaScriptで扱える最大値 `Number.MAX_VALUE = 1.7976931348623157e+308`まで表示することができます。しかし、正確性は保障されないことに変わりはありません。

`bigint`型は、型安全保障(type guard)も他の型と同様に利用できます。

`number`型と`bigint`型は互換性がありません。
2つの型を使って演算を実行するには、型変換(cast)をすることで実行可能になります。[参考: mrsekutの備忘録](https://mrsekut.site/?p=3354)


```ts
let foo: bigint = BigInt(100);         // BitInt関数により初期化
let bar: bigint = 100n;                // BitIntリテラルによる割り当て
let integer: number = 10;              // numberリテラルによる割り当て

console.log(foo + bar);                // OK
console.log(foo + integer);            // Error, Type 'bigint' is not assignable to type 'number'.
console.log(foo + BigInt(integer));    // OK

if (typeof foo === "bigint") {         // タイプガードも利用可能
    console.log("'foo' is a bigint.");
} else {
    console.log("'foo' is a floating-point number.");
}
```


<a id="string"></a>

## String
Webページやサーバー用のJavaScriptでプログラムを作成する時に、`boolean`、`number`に加えてもう一つの型はテキストデータです。
他の言語と同様に、テキストデータを参照するために`string`を使用します。
また、JavaScriptと同様に、TypeScriptも **"二重引用符(double quotes)"** または **'一重引用符(single quotes)'** を使用して文字列データを囲みます。
JavaScriptとTypeScriptではCやC#、Javaとは違い`char`型が存在しないため、一重引用符を使用することができます。

```ts
let color: string = "blue";
color = 'red';
```

**テンプレート文字列**も使用することができ、複数行にまたがり式を埋め込むことができます。
これらの文字列は \`backtick/backquote\` で囲まれ、埋め込み式は ${ expr } です。
複数行にまたがって代入するときは、コード内のインデントも反映されてしまうので注意してください。

```ts
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.`;
```

上記の変数`sentence`は、次のような宣言と同等です。

```ts
let sentence: string =
  "Hello, my name is " + fullName + ".\n\n" +
  "I'll be " + (age + 1) + " years old next month.";
```

<a id="array"></a>

## Array
TypeScriptではJavaScriptと同様に値の配列操作ができます。  
配列型は2つの方法のいずれかで記述できます。最初の方法では、要素の型に続いて`[]`を使用してその要素型の配列を宣言します。

```ts
let list: number[] = [1, 2, 3];
```

2つ目は、ジェネリクスである`Array<elemType>`を使用する方法です。

```ts
let list: Array<number> = [1, 2, 3];
```

どちらの方法であってもJavaScriptにトランスパイルすると同じ配列になります。


<a id="symbol"></a>

## Symbol

`symbol`は、ECMAScript 2015から導入された`number`や`string`のようなプリミティブなデータタイプです。
`symbol`の値は、`Symbol`のコンストラクタによって生成されます。

```ts
let sym1 = Symbol();
let sym2 = Symbol("key"); // stringキーのオプション
```

`Symbol`は、不変(immutable)であり、一意(unique)です。

```ts
let sym2 = Symbol("key");
let sym3 = Symbol("key");

sym2 === sym3 // Symbolは一意のため、結果はfalseです
```

`string`型のように`Symbol`はオブジェクトプロパティのユニークキーとして使用できます。

```ts
const sym = Symbol();
let obj = {
    [sym]: "value"
};

console.log(obj[sym]);  // "value"
```

`Symbol`は、オブジェクトプロパティとクラスメンバーのような算出プロパティの宣言としても使用できます。

```ts
const getClassNameSymbol = Symbol();

class C {
    [getClassNameSymbol](){
       return "C";
    }
}

let c = new C();
let className = c[getClassNameSymbol](); // "C"
```
以下、`Symbol`が持つ拡張機能です。詳細は[ハンドブック](https://www.typescriptlang.org/docs/handbook/symbols.html)をご覧ください。

- Symbol.hasInstance
- Symbol.isConcatSpreadable
- Symbol.iterator
- Symbol.match
- Symbol.replace
- Symbol.search
- Symbol.species
- Symbol.split
- Symbol.toPrimitive
- Symbol.toStringTag
- Symbol.unscopables

<a id="tuple"></a>

## Tuple

タプル型を使用すると、型はわかっているが同じである必要のない固定数の要素で配列を表現できます。
例えば、文字列と数値のペアとして値を表すことができます。

```ts
// タプル型の宣言
let x: [string, number];
// 正しい初期化
x = ["hello", 10]; // OK
// 正しくない初期化
x = [10, "hello"]; // Error
```

要素が存在するインデックスで要素を取得すると、正しい型が取得できます。

```ts
console.log(x[0].substring(1)); // OK
console.log(x[1].substring(1)); // Error, number は substring を持っていません
```

要素が存在しないインデックスで要素を取得しようとすると、エラーが発生します。

```ts
let x: [string, number];
x = ["hello", 10];

x[3] = "world"; // Error, プロパティ '3' は 型 '[string, number]' に存在しません
console.log(x[5].toString()); // Error, プロパティ '4' は 型 '[string, number]' に存在しません
```

<a id="enum"></a>

## Enum
JavaScriptでは存在していない列挙型ですが、TypeScriptでは列挙型として`enum`があります。
C# のような言語と同様に`enum`は、数値のセットによってわかりやすい名前を付ける方法です。
ちなみにJavaScriptでも、連想配列(辞書型)として列挙型のように振舞うことは可能です。

```ts
enum Color {
  Red,
  Green,
  Blue
}
let c: Color = Color.Green;
```

デフォルトでは、列挙型は 0 から採番を始めます。手動で採番をするにはメンバーのいずれかに値を与えると変更することが可能です。
下記の例では、 0 ではなく 1 から採番しています。

```ts
enum Color {
  Red = 1,
  Green,
  Blue
}
let c: Color = Color.Green;
```

また、全て手動で設定することも可能です。

```ts
enum Color {
  Red = 1,
  Green = 2,
  Blue = 4
}
let c: Color = Color.Green;
```

列挙型の便利なところは、その値から列挙型した名前を取得できるところです。
例えば、下記の例では値が 2 であるのにもかかわらず、`Color`という列挙型で何にマップされているかわからない場合、対応する名前を検索できます。

```ts
enum Color {
  Red = 1,
  Green,
  Blue
}
let colorName: string = Color[2];

console.log(colorName); // value値 2 に対応する 'Green' が表示されます
```

例では数値をvalueとして設定していますが、文字列も設定することが可能です。
その場合、自動採番はされないので全ての列挙に対して値を設定してください。

```ts
enum Color {
  Red = "red",
  Green = "green",
  Blue = "blue"
}
let c: Color = Color.Green;
```

<a id="any"></a>

## Any
プログラマはアプリケーションの作成時に、型が不明な変数を宣言する場合があります。動的なコンテンツやユーザーまたはサードパーティライブラリ、Native JavaScriptから型が不明な値が返ってくることがあるからです。
プログラマはそれらの不明な型変数をオプトアウトして、コンパイルを通す必要があります。
その時は、`any`型で宣言します。

```ts
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // 問題なく、booleanを代入できます。
```

`any`型は既存のJavaScriptを操作する協力な方法であり、コンパイル中にタイプチェックを徐々にオプトイン/アウトできます。

```ts
let notSure: any = 4;
notSure.ifItExists(); // OK, 実行時には ifItExists はおそらく存在している
notSure.toFixed(); // OK, toFixed は存在している (コンパイラはチェックしない)

let prettySure: Object = 4;
prettySure.toFixed(); // Error, 'Object'型に 'toFixed' は存在しません
```

> `Object`は非プリミティブ型です。そのため、使用は推奨していません。[Do's and Don'ts](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html)

`any`型は、使用する型の一部を知っている場合にも便利ですが、それがすべてではありません。
例えば、`any`型の配列は様々な型が混在する場合があります。

```ts
let list: any[] = [1, true, "free"];

list[1] = 100;
```

<a id="unknown"></a>

## Unknown
`unknown`型は、型安全な`any`型です。全ての変数宣言で`unknown`型を使うことができますが、
`unknown`型はそれ自体と型注釈、制御フローベースの型絞り込み機能を持ちません。
つまり、実際に使用する際には型を明確に指定する必要があります。

[TypeScript 3.0 unknown - サンプルコードと解説](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#new-unknown-top-type)

<a id="nullAndUndefined"></a>

## Null and Undefined

TypeScriptでは、`undefined`と`null`の両方が明示的な型としてそれぞれ存在しています。
`void`型のように単独ではあまり役に立ちません。

```ts
// これらの型指定された変数に対して他の値を割り当てることはできません
let u: undefined = undefined;
let n: null = null;
```

デフォルトでは、`null`と`undefined`は他の全ての型の派生型です。
つまり`number`のようなものに`null`と`undefined`を割り当てることができます。

しかし、`--strictNullChecks`オプションを使うと`null`と`undefined`は、`any`型にのみ割り当てが可能です。(例外として`undefined`は`void`型に割り当て可能です。)  
これにより、たくさんの一般的なエラーの助けになります。
一つの変数に対して`string`, `null`, `undefined`をそれぞれ割り当てたい時は、`string | null | undefined`の様な複合型(ユニオン型)を使うことができます。

> `--strictNullChecks`オプションは使用することを推奨していますが、このハンドブックではオフにしています。

<a id="never"></a>

## Never

`never`型は何も発生しない型として表現されます。
使用例として、常に例外をスローする関数式やアロー関数式、または決して`return`されないアロー式の戻り値型などがあります。
また、変数は決して真にならない場合、型推論では`never`型を推論します。

`never`型は、全ての型の派生型なので、全ての変数に指定できます。
さらに、型無し(no type)は`never`型の派生型であり、`never`型を割り当て可能です。(`never`型自身を除いて)
ただし、`any`型に`never`型を割り当てることはできません。

`never`型を返す関数のサンプルをいくつか紹介します。

```ts
// この関数は途中でthrowされているため、完了することはありません
function error(message: string): never {
    throw new Error(message);
}

// 上記のerror関数の戻り値がnever型なので、戻り値の型推論結果はnever型です
function fail() {
    return error("Something failed");
}

// この関数は無限ループにより、完了することはありません
function infiniteLoop(): never {
    while (true) {
    }
}
```

<a id="object"></a>

## Object

`object`型は非プリミティブな型を表します。
`object`とは違い、`number`, `string`, `boolean`, `bigint`, `symbol`, `null`, `undefined` はプリミティブです。
`object`型を使うと、`Object.create`のようなAPIを適切に表現することができます。

```typescript
declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
```

<a id="typeAssertions"></a>

## 型注釈

TypeScriptプログラマは、TypeScriptコンパイラよりもその変数の型について把握している状況があります。
エンティティについて現在の型よりも正確で具体的な型を理解しているときに起こります。

型注釈は、コンパイラに "trust me, I know what I’m doing." (信じて、私は把握しているよ！)と伝える方法です。
TypeScriptでは、他言語のキャストにあるような、型チェックや変数の再構築はしません。
型注釈は実行に影響はありません。コンパイル時に影響する機能です。TypeScriptは、プログラマが型チェックをしている前提で動作します。

型注釈を設定する方法は2種類あります。
"<>"(angle-bracket)記法と `as` 記法です。

```ts
let someValue: any = "this is a string";

let angleBracket: number = (<string>someValue).length;  // <>記法
let asBracket: number = (someValue as string).length;   // as記法
```

2つのサンプルは同等です。どちらを使用するかは好みです。  
ただし、`JSX`でTypeScriptを使用する場合は `as` 記法のみ許可されます。

<a id="let"></a>

## <span style="color: orange">let</span>に関するメモ

既にお気づきかと思いますが、ここまでのサンプルではJavaScriptの`var`の代わりに`let`を使用してきました。
`let`はES2015でJavaScriptに導入され、`var`よりも安全であるため、現在では標準とみなされています。
JavaScriptの多くの問題は`let`を使用して軽減されるため、可能な限り`var`の代わりに`let`を使用する必要があります。
(詳しくは、「let var scope」で検索してみてください。)