メインコンテンツまでスキップ

[Easy] 基本型と型アノテーション

1. What are TypeScript Basic Types?

TypeScript の基本型にはどのようなものがありますか?

TypeScript は変数、関数のパラメータ、戻り値の型を定義するための多くの基本型を提供しています。

基本型

// 1. number:数値(整数、浮動小数点数)
let age: number = 30;
let price: number = 99.99;

// 2. string:文字列
let name: string = 'John';
let message: string = `Hello, ${name}!`;

// 3. boolean:真偽値
let isActive: boolean = true;
let isCompleted: boolean = false;

// 4. null:空値
let data: null = null;

// 5. undefined:未定義
let value: undefined = undefined;

// 6. void:戻り値なし(主に関数で使用)
function logMessage(): void {
console.log('Hello');
}

// 7. any:任意の型(使用を避けるべき)
let anything: any = 'hello';
anything = 42;
anything = true;

// 8. unknown:未知の型(any より安全)
let userInput: unknown = 'hello';
// userInput.toUpperCase(); // ❌ エラー:先に型チェックが必要

// 9. never:決して発生しない値(決して返らない関数に使用)
function throwError(): never {
throw new Error('Error');
}

// 10. object:オブジェクト(あまり使わない、interface の使用を推奨)
let user: object = { name: 'John' };

// 11. array:配列
let numbers: number[] = [1, 2, 3];
let names: Array<string> = ['John', 'Jane'];

// 12. tuple:タプル(固定長・固定型の配列)
let person: [string, number] = ['John', 30];

2. Type Annotations vs Type Inference

型アノテーション vs 型推論

型アノテーション(Type Annotations)

定義:変数の型を明示的に指定すること。

// 型を明示的に指定
let age: number = 30;
let name: string = 'John';
let isActive: boolean = true;

// 関数のパラメータと戻り値
function add(a: number, b: number): number {
return a + b;
}

型推論(Type Inference)

定義:TypeScript が初期値に基づいて自動的に型を推論すること。

// TypeScript が自動的に number と推論
let age = 30; // age: number

// TypeScript が自動的に string と推論
let name = 'John'; // name: string

// TypeScript が自動的に boolean と推論
let isActive = true; // isActive: boolean

// 関数の戻り値も自動的に推論される
function add(a: number, b: number) {
return a + b; // 戻り値を自動的に number と推論
}

型アノテーションを使用すべきとき

型を明示的に指定すべき場合

// 1. 変数宣言時に初期値がない場合
let value: number;
value = 10;

// 2. 関数パラメータ(指定必須)
function greet(name: string): void {
console.log(`Hello, ${name}!`);
}

// 3. 関数の戻り値(明示的な指定を推奨)
function calculate(): number {
return 42;
}

// 4. 複雑な型で推論が正確でない可能性がある場合
let data: { name: string; age: number } = {
name: 'John',
age: 30,
};

3. Common Interview Questions

よくある面接の質問

問題 1:型推論

以下のコードにおける各変数の型を説明してください。

let value1 = 10;
let value2 = 'hello';
let value3 = true;
let value4 = [1, 2, 3];
let value5 = { name: 'John', age: 30 };
クリックして回答を表示
let value1 = 10;                    // number
let value2 = 'hello'; // string
let value3 = true; // boolean
let value4 = [1, 2, 3]; // number[]
let value5 = { name: 'John', age: 30 }; // { name: string; age: number }

解説

  • TypeScript は初期値に基づいて自動的に型を推論する
  • 配列は要素の型の配列として推論される
  • オブジェクトはオブジェクトの構造型として推論される

問題 2:型エラー

以下のコードの型エラーを見つけてください。

let age: number = 30;
age = 'thirty';

let name: string = 'John';
name = 42;

let isActive: boolean = true;
isActive = 'yes';

let numbers: number[] = [1, 2, 3];
numbers.push('4');
クリックして回答を表示
let age: number = 30;
age = 'thirty'; // ❌ Type 'string' is not assignable to type 'number'

let name: string = 'John';
name = 42; // ❌ Type 'number' is not assignable to type 'string'

let isActive: boolean = true;
isActive = 'yes'; // ❌ Type 'string' is not assignable to type 'boolean'

let numbers: number[] = [1, 2, 3];
numbers.push('4'); // ❌ Argument of type 'string' is not assignable to parameter of type 'number'

正しい書き方

let age: number = 30;
age = 30; // ✅

let name: string = 'John';
name = 'Jane'; // ✅

let isActive: boolean = true;
isActive = false; // ✅

let numbers: number[] = [1, 2, 3];
numbers.push(4); // ✅

問題 3:any vs unknown

anyunknown の違いを説明し、どちらを使用すべきか説明してください。

// ケース 1:any を使用
function processAny(value: any): void {
console.log(value.toUpperCase()); // ?
}

// ケース 2:unknown を使用
function processUnknown(value: unknown): void {
console.log(value.toUpperCase()); // ?
}
クリックして回答を表示

ケース 1:any を使用

function processAny(value: any): void {
console.log(value.toUpperCase()); // ⚠️ コンパイルは通るが、実行時にエラーが発生する可能性あり
}

processAny('hello'); // ✅ 正常に実行
processAny(42); // ❌ 実行時エラー:value.toUpperCase is not a function

ケース 2:unknown を使用

function processUnknown(value: unknown): void {
// console.log(value.toUpperCase()); // ❌ コンパイルエラー:Object is of type 'unknown'

// 先に型チェックが必要
if (typeof value === 'string') {
console.log(value.toUpperCase()); // ✅ 安全
}
}

違いの比較

特性anyunknown
型チェック完全に無効化使用前にチェックが必要
安全性安全でない安全
使用推奨使用を避ける推奨

ベストプラクティス

// ✅ 推奨:unknown を使用し、型チェックを行う
function processValue(value: unknown): void {
if (typeof value === 'string') {
console.log(value.toUpperCase());
} else if (typeof value === 'number') {
console.log(value.toFixed(2));
}
}

// ❌ 避ける:any を使用
function processValue(value: any): void {
console.log(value.toUpperCase()); // 安全でない
}

問題 4:配列の型

以下の配列の型宣言の違いを説明してください。

let arr1: number[];
let arr2: Array<number>;
let arr3: [number, string];
let arr4: any[];
クリックして回答を表示
// 1. number[]:数値配列(推奨される書き方)
let arr1: number[] = [1, 2, 3];
arr1.push(4); // ✅
arr1.push('4'); // ❌ エラー

// 2. Array<number>:ジェネリック配列(number[] と同等)
let arr2: Array<number> = [1, 2, 3];
arr2.push(4); // ✅
arr2.push('4'); // ❌ エラー

// 3. [number, string]:タプル(Tuple)- 固定長・固定型
let arr3: [number, string] = [1, 'hello'];
arr3[0] = 2; // ✅
arr3[1] = 'world'; // ✅
arr3[2] = true; // ❌ エラー:長さが 2 を超えている
arr3.push('test'); // ⚠️ TypeScript は許可するが、非推奨

// 4. any[]:任意の型の配列(非推奨)
let arr4: any[] = [1, 'hello', true];
arr4.push(42); // ✅
arr4.push('world'); // ✅
arr4.push(false); // ✅(ただし型チェックが失われる)

使用に関するアドバイス

  • 一般的な配列:number[] または Array<number> を使用
  • 固定構造:タプル [type1, type2] を使用
  • any[] の使用を避け、具体的な型または unknown[] を優先

問題 5:void vs never

voidnever の違いと使用シーンを説明してください。

// ケース 1:void
function logMessage(): void {
console.log('Hello');
}

// ケース 2:never
function throwError(): never {
throw new Error('Error');
}

function infiniteLoop(): never {
while (true) {
// 無限ループ
}
}
クリックして回答を表示

void

  • 用途:関数が値を返さないことを表す
  • 特徴:関数は正常に終了するが、値を返さない
  • 使用シーン:イベントハンドラ、副作用関数
function logMessage(): void {
console.log('Hello');
// 関数は正常に終了し、値を返さない
}

function onClick(): void {
// クリックイベントを処理、戻り値は不要
}

never

  • 用途:関数が決して正常に終了しないことを表す
  • 特徴:関数がエラーをスローするか、無限ループに入る
  • 使用シーン:エラー処理、無限ループ、型ガード
function throwError(): never {
throw new Error('Error');
// ここには到達しない
}

function infiniteLoop(): never {
while (true) {
// 終了しない
}
}

// 型ガードでの使用
function assertNever(value: never): never {
throw new Error(`Unexpected value: ${value}`);
}

違いの比較

特性voidnever
関数の終了正常に終了決して終了しない
戻り値undefined戻り値なし
使用シーン戻り値のない関数エラー処理、無限ループ

4. Best Practices

ベストプラクティス

推奨される方法

// 1. 型推論を優先的に使用
let age = 30; // ✅ TypeScript に推論させる
let name = 'John'; // ✅

// 2. 関数のパラメータと戻り値は型を明示的に指定
function calculate(a: number, b: number): number {
return a + b;
}

// 3. any ではなく unknown を使用
function processValue(value: unknown): void {
if (typeof value === 'string') {
console.log(value.toUpperCase());
}
}

// 4. 具体的な配列型を使用
let numbers: number[] = [1, 2, 3]; // ✅
let names: Array<string> = ['John', 'Jane']; // ✅

// 5. タプルで固定構造を表現
let person: [string, number] = ['John', 30]; // ✅

避けるべき方法

// 1. any の使用を避ける
let value: any = 'hello'; // ❌

// 2. 不要な型アノテーションを避ける
let age: number = 30; // ⚠️ let age = 30; に簡略化できる

// 3. object 型の使用を避ける
let user: object = { name: 'John' }; // ❌ interface を使用する方がよい

// 4. 混合型配列を避ける(必要でない限り)
let mixed: (string | number)[] = ['hello', 42]; // ⚠️ 本当に必要かどうか検討

5. Interview Summary

面接のまとめ

クイックリファレンス

基本型

  • number, string, boolean, null, undefined
  • void(戻り値なし), never(決して返らない)
  • any(任意の型、使用を避ける), unknown(未知の型、使用推奨)

型アノテーション vs 推論

  • 型アノテーション:明示的に指定 let age: number = 30
  • 型推論:自動推論 let age = 30

配列の型

  • number[] または Array<number>:一般的な配列
  • [number, string]:タプル(固定構造)

面接の回答例

Q: TypeScript にはどのような基本型がありますか?

"TypeScript は多くの基本型を提供しています。number、string、boolean、null、undefined が含まれます。さらに特殊な型もあります。void は戻り値がないことを表し、主に関数で使用されます。never は決して発生しない値を表し、決して返らない関数に使用されます。any は任意の型ですが、使用を避けるべきです。unknown は未知の型で、any より安全であり、使用前に型チェックが必要です。また、配列型 number[] とタプル型 [number, string] もあります。"

Q: any と unknown の違いは何ですか?

"any は型チェックを完全に無効にし、任意のプロパティやメソッドを直接使用できますが、これは安全ではありません。unknown は使用前に型チェックを行う必要があり、より安全です。例えば unknown を使用する場合、まず typeof で型をチェックし、確認後に対応するメソッドを呼び出す必要があります。any よりも unknown の使用を優先することを推奨します。"

Reference