🦕

よく使う便利なTypeScriptの型システムをわかりやすくまとめてみた

2024/04/02に公開

インデックス型クエリ keyof ◯◯Type

keyofを使って特定の型からその型が持つプロパティのキー名の集合(ユニオン型)を作成することができます。

下記の例では、ProfileType型があり、この型はname、age、hobbyという3つのプロパティを持っています。ここでkeyof ProfileTypeを使用すると、この型のプロパティキーのユニオンである"name" | "age" | "hobby"を取得できます。

type ProfileType = {
  name: string;
  age: number;
  hobby: string;
};

const profile: ProfileType = {
  name: "Taro",
  age: 30,
  hobby: "Photography",
};

const key: keyof ProfileType = "hobby";

ブラケット記法 []

変数を使ってオブジェクトのプロパティに動的にアクセスすることができます。

先ほどのconst key: keyof ProfileType = "hobby";の記述がなくてもprofile[key]は使用できますが、keyの型を適切に定義することでTypeScriptの型安全性を活用することができます。

console.log(profile[key]); // "Photography"

インデックス署名 [key: 型]

通常、オブジェクトのプロパティはコード上で静的に定義されますが、動的なキーを持つオブジェクトの場合、それらのキーと値の型を事前に指定できないことがあります。インデックス署名を使用すると、動的なプロパティのキーと値の型を事前に定義でき、これによりコードの型安全性が向上します。

// ①
interface User {
  id: number;
  name: string;
  email: string;
}

interface UserDictionary {
  [userId: number]: User;
}

const users: UserDictionary = {
  1: { id: 1, name: "Mike", email: "john@example.com" },
  2: { id: 2, name: "Alice", email: "jane@example.com" },
};

console.log(users[1].name); // "Mike"

// ②
interface AppConfig {
  [key: string]: string | number | boolean;
}

const config: AppConfig = {
  theme: "dark",
  version: 1.0,
  notificationsEnabled: true,
};

console.log(config.theme); // "dark"

typeof 演算子

基本的なデータ型を調べることができます。
nullは、オブジェクトとして表示されるので注意してください。

// 数値
console.log(typeof 1);             // "number"

// 文字列
console.log(typeof 'こんにちは');   // "string"

// ブール値
console.log(typeof true);           // "boolean"

// オブジェクト
console.log(typeof {name: 'Alice'}); // "object"

// 関数
function myFunction() {}
console.log(typeof myFunction);      // "function"

// undefined
let notDefined;
console.log(typeof notDefined);     // "undefined"

// null(注: JavaScriptの歴史的な理由で "object" と表示される)
console.log(typeof null);           // "object"

// シンボル(ES6以降)
console.log(typeof Symbol('id'));   // "symbol"

型述語 is

特定の関数やメソッドが呼び出された後に引数や返り値が特定の型であることを保証するために使われます。

下記の例では、isNumberは、任意の入力valueを受け取り、その型がnumberであるかどうかをチェックしています。戻り値の型述語value is numberは、この関数がtrueを返す場合にvaluenumber型であることをTypeScriptの型システムに示しています。

const values: any[] = [10, "hello", true, 42];

const isNumber = (value: any): value is number => typeof value === 'number';

values.forEach(value => {
  if (isNumber(value)) {
    console.log(`${value} is a number, and its double is ${value * 2}`);
  } else {
    console.log(`${value} is not a number`);
  }
});

// 10 is a number, and its double is 20
// hello is not a number
// true is not a number
// 42 is a number, and its double is 84

型アサーション as

asを使うことで、型チェッカーの推論に関わらず、任意の型を強制的に割り当てることができます。

interface Data {
  id: number | string;
}

const data: Data = { id: '123' };

// idプロパティが数値かもしれないが、この場合は文字列であると断定
const idString = data.id as string;

console.log(idString); // 文字列として扱われるので'123'

is keyof typeofの例

下記の例では、skills[skillKey]の箇所でブラケット記法 []も使用しています。

type Skill = {
  technology: string;
  yearsOfExperience: number;
};

type UserProfile = {
  name: string;
  age: number;
  profession: string;
  skills: {
    skill1: Skill;
    skill2: Skill;
    skill3: Skill;
  };
};

const userProfile: UserProfile = {
  name: "Mike",
  age: 30,
  profession: "Software Engineer",
  skills: {
    skill1: { technology: "JavaScript", yearsOfExperience: 5 },
    skill2: { technology: "TypeScript", yearsOfExperience: 3 },
    skill3: { technology: "React", yearsOfExperience: 2 }
  }
};

const technologies = [];

for (let i = 1; i <= 3; i++) {
  // skillを指定するためのキーを生成
  const skillKey = `skill${i}` as keyof typeof userProfile.skills;
  // skillKeyに格納されているキー("skill1")を使用して
  // userProfile.skills オブジェクトから対応するスキルオブジェクト
  const skill = userProfile.skills[skillKey];

  // スキルが存在する場合のみ配列に追加する
  if (skill) {
    // 1回目のループの場合skill.technologyはskill1.technology
    technologies.push(skill.technology);
  }
}
// technologiesは['JavaScript', 'TypeScript', 'React']になります

型エイリアス

型に名前を付けることができます。

type StringOrNumber = string | number;

const printId = (id: StringOrNumber) => {
  console.log(id);
}

ユニオン型 string | number

複数の型をパイプ(|)で結ぶ書き方です。

const printValue = (value: string | number) => {
  console.log(value);
}

printValue(123); // 数値を引数として受け入れます
printValue("Hello, World!"); // 文字列を引数として受け入れます

型キャスト  Number(○○)

あるデータ型の値を別のデータ型に変換します。

//数値への変換 文字列"123"を数値123に変換
Number("123");

//文字列への変換 数値123を文字列"123"に変換
String(123);

// ブール値への変換 数値1をブール値trueに変換
 Boolean(1)

終わりに

何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉

Discussion