0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

[TypeScript] interfaceの継承で、プロパティを入れたくない場合に使うOmit型

Last updated at Posted at 2024-06-17

自己紹介

こんにちは、よわよわエンジニアのちゃったまです。
業務でTypeScriptを使っているのですが、TypeScriptの恩恵を享受しきれていない今日この頃です。

TypeScriptの恩恵の一つ、Omit型について書いてみようと思います。


Omit型

interfaceを継承して、新たにinterfaceを定義したいけど、
継承させたくないプロパティがある場合ってありますよね。

例えば、以下のinterfaceで、「description」を除きつつ継承させたい場合。


// 継承元
export interface Member {
  name: string;
  email: string;
  role: Role;
  description: string; // こいつは継承させたくない
}

そんな時に使うのがOmit型です。
Omit型を使用すると、次のように書くことができます。


export interface SubMember extends Omit<Member, 'description'> {
   department: string;
}

const subMember: SubMember = {
  // descriptionは引き継がれない
  name: 'John Doe',
  email: 'john.doe@example.com',
  role: 'Admin',
  department: 'sales'
}

「description」が除外された形で、元のinterfaceを継承しています。

注意点として、プロパティを持たないinterfaceは定義できません。


// これはエラーになる
export interface SubMember extends Omit<Member, 'description'> {
}


代わりにtypeで定義することはできます。

参考:interfaceとtypeの違い


export type SubMember = Omit<Member, 'description'>;


複数のプロパティを継承元から除外したい場合は次のように記述します。

「description」と「role」を除外する場合。


export type SubMember = Omit<Member, 'description' | 'role'>;

const subMember: SubMember = {
  // description, roleは引き継がれない
  name: 'John Doe',
  email: 'john.doe@example.com',
};


Omit型の活用方法

上記が一般的な使用方法です。
他にどういう使用方法があるかChatGPT-4oに聞いてみました。

1. 特定のプロパティを再定義する

Omitを使用して特定のプロパティを除外し、その後にそのプロパティを再定義することで、新しい型を作成することができます。

interface Base {
  id: string;
  name: string;
  age: number;
  role: string;
}

// idプロパティの型を変更する
type ModifiedBase = Omit<Base, 'id'> & { id: number };

const modified: ModifiedBase = {
  id: 123,
  name: 'Alice',
  age: 30,
  role: 'Developer'
};

これはあまり使わなそうだな・・・同じプロパティ名なのに型が違うとか混乱しそうだし
用途あるかなぁ。

2. ネストされたオブジェクトのプロパティを除外する

Omitを使って、ネストされたオブジェクトのプロパティを除外することもできます。

interface Nested {
  id: string;
  details: {
    age: number;
    address: string;
    phone: string;
  };
}

// ネストされたdetailsオブジェクトのaddressとphoneプロパティを除外する
type ModifiedNested = Omit<Nested, 'details'> & {
  details: Omit<Nested['details'], 'address' | 'phone'>
};

const modifiedNested: ModifiedNested = {
  id: '001',
  details: {
    age: 25
    // addressとphoneプロパティは存在しません
  }
};

うーん。これも使うかな?微妙だ。
detailsを型定義してそこでOmit型を使用した方がいいような気がするけど
短く書けるしこっちの方がいいのかな。


3. 動的なプロパティ除外

動的にプロパティを除外するためのユーティリティ型を作成することもできます。

type DynamicOmit<T, K extends keyof T> = Omit<T, K>;

// 使用例
interface User {
  id: string;
  name: string;
  email: string;
  age: number;
}

type UserWithoutEmail = DynamicOmit<User, 'email'>;

const user: UserWithoutEmail = {
  id: '123',
  name: 'John Doe',
  age: 45
  // emailプロパティは存在しません
};

これはわかりやすくていいかも。

4. プロパティ名のリストから除外

プロパティ名のリストを使って複数のプロパティを除外するユーティリティ型を作成することもできます。

 type RemoveProperties<T, K extends (keyof T)[]> = Omit<T, K[number]>;

 // 使用例
 type UserWithoutEmailAndAge = RemoveProperties<User, ['email', 'age']>;

 const userWithoutEmailAndAge: UserWithoutEmailAndAge = {
  id: '123',
  name: 'John Doe'
  // emailとageプロパティは存在しません
 };

3の拡張版だね。

まとめ

Omitの基本的な使用については知っていたものの、いろんな使い方があるんだなと思った。
TypeScriptマスターへの道は果てしなく続く・・・。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?