型安全性を保ちながらコードを柔軟にする! TypeScriptにおけるジェネリック型のオプション化

2024-04-09

TypeScriptでジェネリック型をオプションにする方法

デフォルト値を使う

ジェネリック型にデフォルト値を設定することで、ジェネリック型を省略することができます。例えば、以下のコードでは、T型にデフォルト値としてstring型を設定しています。

function foo<T = string>(arg: T): T {
  return arg;
}

const bar = foo(123); // bar: number
const baz = foo("abc"); // baz: string

このコードでは、foo関数を呼び出す際に、ジェネリック型を省略することができます。bar変数には数値123baz変数には文字列"abc"が格納されます。

undefinedまたはnullを使う

ジェネリック型にundefinedまたはnullを設定することで、ジェネリック型を省略することができます。ただし、この方法を使う場合は、ジェネリック型がundefinedまたはnullになる可能性があることを考慮する必要があります。

function foo<T extends undefined | null>(arg: T): T {
  return arg;
}

const bar = foo(undefined); // bar: undefined
const baz = foo(null); // baz: null

Partial型を使うことで、ジェネリック型のプロパティをオプションにすることができます。例えば、以下のコードでは、T型のプロパティnameageをオプションにしています。

interface Person {
  name: string;
  age: number;
}

function foo<T extends Partial<Person>>(arg: T): T {
  return arg;
}

const bar = foo({ name: "John" }); // bar: { name: "John" }
const baz = foo({ age: 30 }); // baz: { age: 30 }

このコードでは、foo関数を呼び出す際に、ジェネリック型Tのプロパティnameageを省略することができます。bar変数にはnameプロパティのみを持つオブジェクト、baz変数にはageプロパティのみを持つオブジェクトが格納されます。

Union型を使うことで、ジェネリック型に複数の型を指定することができます。例えば、以下のコードでは、T型にstring型とnumber型を指定しています。

function foo<T extends string | number>(arg: T): T {
  return arg;
}

const bar = foo("abc"); // bar: string
const baz = foo(123); // baz: number

TypeScriptでジェネリック型をオプションにする方法はいくつかあります。それぞれの方法にはメリットとデメリットがあるので、状況に合わせて使い分けることが重要です。




デフォルト値を使う

function foo<T = string>(arg: T): T {
  return arg;
}

const bar = foo(123); // bar: number
const baz = foo("abc"); // baz: string

undefinedまたはnullを使う

function foo<T extends undefined | null>(arg: T): T {
  return arg;
}

const bar = foo(undefined); // bar: undefined
const baz = foo(null); // baz: null

Partial型を使う

interface Person {
  name: string;
  age: number;
}

function foo<T extends Partial<Person>>(arg: T): T {
  return arg;
}

const bar = foo({ name: "John" }); // bar: { name: "John" }
const baz = foo({ age: 30 }); // baz: { age: 30 }

Union型を使う

function foo<T extends string | number>(arg: T): T {
  return arg;
}

const bar = foo("abc"); // bar: string
const baz = foo(123); // baz: number

ジェネリック型を複数回使う

function foo<T, U>(arg1: T, arg2: U): [T, U] {
  return [arg1, arg2];
}

const bar = foo("abc", 123); // bar: ["abc", 123]

ジェネリック型に制約をつける

function foo<T extends number | string>(arg: T): T {
  return arg;
}

// エラー: 'boolean'型は'number'型または'string'型ではない
// const bar = foo(true);

ジェネリック型を利用した関数型

type Foo<T> = (arg: T) => T;

const bar: Foo<string> = (arg) => arg;

const baz = bar("abc"); // baz: "abc"



ジェネリック型をオプションにする他の方法

interface Person {
  name: string;
  age: number;
}

function foo<T extends Partial<Person>>(arg: T): T {
  return arg;
}

const bar = foo({ name: "John" }); // bar: { name: "John" }
const baz = foo({ age: 30 }); // baz: { age: 30 }

const qux = foo({ name: "John", age: 30 }); // qux: { name: "John", age: 30 }
interface Person {
  name: string;
  age: number;
}

function foo<T extends keyof Person>(arg: T): Person[T] {
  return arg;
}

const bar = foo("name"); // bar: string
const baz = foo("age"); // baz: number

Record型を使うことで、ジェネリック型をキーと値のペアの型にすることができます。例えば、以下のコードでは、T型をキーと値のペアの型にしています。

function foo<T extends Record<string, any>>(arg: T): T {
  return arg;
}

const bar = foo({ name: "John" }); // bar: { name: "John" }
const baz = foo({ age: 30 }); // baz: { age: 30 }

TypeScriptのジェネリック型は、コードを汎用化するための強力なツールです。上記のサンプルコードを参考に、さまざまな状況でジェネリック型を活用してみてください。


generics typescript


オブジェクトの参照渡しとコピーの違い

オブジェクトの浅いコピーを作成するには、Object. assign() メソッドを使用できます。 この方法は、オブジェクトのプロパティとその値を新しいオブジェクトにコピーしますが、ネストされたオブジェクトはコピーしません。この例では、originalObject のプロパティである name、age、address が clonedObject にコピーされています。 しかし、address プロパティはネストされたオブジェクトであるため、clonedObject の address プロパティは originalObject の address プロパティへの参照となります。...


【徹底解説】Angularでイベントリスナーを動的に追加:3つの方法とサンプルコード

addEventListener メソッドを使用する最も基本的な方法は、addEventListener メソッドを使用することです。この方法は、ネイティブの DOM API を直接呼び出すため、シンプルでわかりやすいです。このコードは、myButton IDを持つ要素に click イベントリスナーを追加します。リスナー関数は、ボタンがクリックされたときに呼び出され、コンソールにメッセージを出力します。...


JavaScript、TypeScript、Angular で Angular2 イベントの型を理解する

Angular2 イベントは、コンポーネント間またはコンポーネントと外部要素間でデータをやり取りするための重要なメカニズムです。これらのイベントを理解し、適切な型を扱うことは、Angular アプリケーションを効果的に開発するために不可欠です。...


TypeScriptデコレータでコードをもっとスマートに!エラー「Unable to resolve signature of class decorator when called as an expression」の解決策付き

TypeScript のデコレータを使用する際に、以下のエラーが発生することがあります。このエラーは、デコレータのシグネチャが正しく定義されていない場合に発生します。原因このエラーには、主に以下の 2 つの原因が考えられます。TypeScript バージョン: TypeScript 5.0 以降では、デコレータに context という引数が追加されました。古いバージョンの TypeScript を使用している場合、この引数が定義されていないため、エラーが発生します。...


TypeScript/Node.js アプリにおける GUID/UUID の概要と実装

GUID (Globally Unique Identifier) と UUID (Universally Unique Identifier) は、どちらも 128 ビットの値で表されるユニークな識別子です。これらの識別子は、データベースレコード、ソフトウェアコンポーネント、ネットワークノードなど、さまざまなエンティティを一意に識別するために使用されます。...


SQL SQL SQL SQL Amazon で見る



【TypeScript初心者でも安心】文字列を数値に変換する3つの方法と各方法の使い分け、さらに役立つ豆知識まで徹底解説

Number() 関数は、文字列を数値に変換する最も簡単な方法です。parseInt() 関数は、文字列を10進数の整数に変換します。各方法の注意点Number() 関数は、文字列の先頭から数値に変換できる部分のみを抽出します。そのため、文字列の末尾に文字が含まれている場合は、その部分は無視されます。