TypeScriptのユニオン型は、型の合併(union)を表現するものです。2つ以上の型から構成される型であり、それらの型のいずれかになる可能性を表現します。TypeScriptにおいてユニオン型を使用する際はパイプ記号(|)を使用します。
let value: string | number;
変数valueは、文字列または数値を格納することができます。
value = 'hello';
value = 42;
関数の引数や戻り値の型にユニオン型を使用することで、より柔軟に対応することができます。
例えば、文字列や数値を引数として受け取る関数を宣言することができます。
function doSomething(arg: string | number) {
// ...
}
文字列や数値を返す関数を宣言することができます。
function getValue(): string | number {
// ...
}
ユニオン型の注意点として、異なる型の値を適切に扱うために、型チェックや型アサーションが必要になる場合があることが挙げられます。例えば、次のようなコードを考えてみましょう。
function doSomething(arg: string | number) {
console.log(arg.length); // Error: Property 'length' does not exist on type 'string | number'.
}
ここで、引数argはstring | numberのユニオン型を持っていますが、lengthプロパティは文字列に対してのみ存在します。これを解決するには、型チェックと型アサーションを使って、この場合argが文字列であることをTypeScriptに伝える必要があります。
function doSomething(arg: string | number) {
if (typeof arg === 'string') {
console.log(arg.length); // ok
} else {
console.log(arg.toString().length); // ok
}
}
doSomething("hello"); // 5
doSomething(10); // 2
また、asキーワードを使って、argが文字列であることをアサーションすることもできます。
function doSomething(arg: string | number) {
console.log((arg as string).length); // ok
}
ただ、上記の型アサーションでは引数が数値型の際に出力ができない点には注意しなければなりません。
function doSomething(arg: string | number) {
console.log((arg as string).length);
}
doSomething("hello"); // 5
doSomething(10); // undefined
型アサーションは型推論を上書きすることができるので上記のようなバグを産む原因にもなります。型アサーションはやむを得ない場合に限り使用するのが良いでしょう。
TypeScriptのもう1つの便利な機能は、型エイリアスです。型エイリアスを使うと、型に名前をつけて、その名前をコード全体で使うことができます。
例えば、文字列と数値のユニオン型に名前を付けたいとしましょう。
type StringOrNumber = string | number;
let myVariable: StringOrNumber;
function myFunction(param: StringOrNumber) {
// 処理
}
これにより、必要なときに文字列と数値のユニオン型を書き出す必要がなく、コード全体でStringOrNumber型を使用することができます。
interface Employee {
name: string;
salary: number;
}
interface Student {
name: string;
major: string;
}
type Staff = Employee | Student;
function printInfo(staff: Staff) {
if ('salary' in staff) {
console.log(`Name: ${staff.name}, Salary: ${staff.salary}`);
} else {
console.log(`Name: ${staff.name}, Major: ${staff.major}`);
}
}
let employee: Employee = {
name: "John Lake",
salary: 50000
};
let student: Student = {
name: "Jane Smith",
major: "Computer Science"
};
printInfo(employee); // "Name: John Lake, Salary: 50000"
printInfo(student); // "Name: Jane Smith, Major: Computer Science"
この例では、EmployeeとStudentの2つのオブジェクトがあり、それぞれが独自のプロパティを有しています。EmployeeとStudentの和であるStaffという型のエイリアスを定義します。これにより、EmployeeとStudentのどちらかをStaff型の変数で使用できるようになります。
また、Staff型の引数を受け取り、渡された人物の情報を表示するprintInfoという関数を定義しています。関数内部では、型ガードを使って引数がsalaryプロパティを持っているかどうかをチェックし、持っていればEmployeeと特定し、それに応じてメッセージを表示し、そうでなければStudentに応じたメッセージを表示します。