Help us understand the problem. What is going on with this article?

TypeScriptの型づけを使う ー Union型、列挙型、型の別名など

More than 1 year has passed since last update.

TypeScriptには、JavaScriptに備わるデータ型だけでなく、ECMAScript 2015の仕様も採り入れて、型や機能が加えられています。それらを試してみましょう。なお、TypeScriptの型づけの基本については、「TypeScript: 基本型」をお読みください。

01 カラー整数値からRGBカラー成分値を配列で返す関数

以下のコード001(TypeScriptサイトのPlaygroundにリンクしています)は、引数に渡したRGBカラーの整数値からRGBごとの成分値を配列で返す関数です。関数は、つぎのように試すことができます。なお、カラー整数値からRGBカラー成分値を求めるビット演算については、「2進数・16進数とビット演算」05「カラー値とビット演算」をお読みください。

let components: number[] = getColorComponents(0xFFCC99);
console.log(components);  //  [ 255, 204, 153 ]
console.log(components[0].toString(16), components[1].toString(16), components[2].toString(16));
// ff cc 99

コード001

function getColorComponents(color: number): number[] {
     let red : number = color >> 16;
     let green: number = color >> 8 & 0xFF;
     let blue: number = color & 0xFF;
     return [red, green, blue];
}

02 戻り値を配列とオブジェクトから選べるようにする

戻り値をオブジェクトで受け取ることもできるようにします。配列かオブジェクトかは、つぎのように関数にブーリアン(論理)値の第2引数を加えて選びます。戻り値がひとつの型に定まりませんので、以下のコード002はとりあえずanyで型づけしました。

let components = getColorComponents(0xFFCC99, false);
console.log(components);  // { red: 255, green: 204, blue: 153 }

コード002

function getColorComponents(color: number, array: boolean): any {
    let red : number = color >> 16;
    let green: number = color >> 8 & 0xFF;
    let blue: number = color & 0xFF;
    if (array) {
        return [red, green, blue];
    } else {
        return {red: red, green: green, blue: blue};
    }
}

03 戻り値に納める値もふたつ選べるようにする

カラー値を16進数表記で知りたい場合もあります。数値では表せませんので、文字列を用いることにします。そのため、関数にブーリアン値の第3引数を加えます。以下のコード003はUnion型|により、変数に数値(number)か文字(string)という型づけをしました。

let components = getColorComponents(0xFFCC99, false, true);
console.log(components);  // { red: 'ff', green: 'cc', blue: '99' }

コード003

function getColorComponents(color: number, array: boolean, string: boolean): any {
    let red : number | string = color >> 16;
    let green: number | string = color >> 8 & 0xFF;
    let blue: number | string = color & 0xFF;
    if (string) {
        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);
    }
    if (array) {
        return [red, green, blue];
    } else {
        return {red: red, green: green, blue: blue};
    }
}

04 オブジェクトを型づけする

関数の戻り値も、anyを改めて、きちんと型づけしましょう。オブジェクトは型をObjectにしたのでは、クラスに定義済みでないプロパティが加えられません。そこで、以下のコード004は、関数の戻り値の型づけにオブジェクト型リテラル(「TypeScript入門 04: オブジェクト型リテラルとインタフェースを使う」02「型定義をつくる」参照)を使いました。なお、配列要素にUnion型を用いるときは、要素の型を丸かっこ()でくくります。

コード004

function getColorComponents(color: number, array: boolean, string: boolean): 
    (number | string)[] |
    {red: number | string, green: number | string, blue: number | string}
{
    let red : number | string = color >> 16;
    let green: number | string = color >> 8 & 0xFF;
    let blue: number | string = color & 0xFF;
    if (string) {
        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);
    }
    if (array) {
        return [red, green, blue];
    } else {
        return {red: red, green: green, blue: blue};
    }
}

05 引数を配列でまとめる

関数に渡すブーリアン値の引数は、あとあとオプションの数が増える場合に備えて、まとめてしまいます。以下のコード005は、引数をブーリアン値の配列にしました。これなら、手直しもさほど多くありません。

let components = getColorComponents(0xFFCC99, [false, true]);
console.log(components);

コード005

function getColorComponents(color: number, format: boolean[]): 
    (number | string)[] |
    {red: number | string, green: number | string, blue: number | string}
{
    let red : number | string = color >> 16;
    let green: number | string = color >> 8 & 0xFF;
    let blue: number | string = color & 0xFF;
    if (format[1]) {
        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);
    }
    if (format[0]) {
        return [red, green, blue];
    } else {
        return {red: red, green: green, blue: blue};
    }
}

06 複数のフラグを列挙型でまとめる

配列でまとめるとコードは簡単なものの、どの要素が何を決めるのかわかりにくくなります。列挙型enumを使うと、数値が名前で表せます。そして、ビット演算を用いれば、複数のフラグがひとつの整数で表せるのです(「2進数・16進数とビット演算」02「複数のフラグをひとつの整数で表す」)。以下のコード006は、列挙型とビット演算を使って書き替えました。

console.log(getColorComponents(0xFFCC99));  // { red: 255, green: 204, blue: 153 }
console.log(getColorComponents(0xFFCC99, Format.STRING));  // { red: 'ff', green: 'cc', blue: '99' }
console.log(getColorComponents(0xFFCC99, Format.ARRAY | Format.STRING));  // [ 'ff', 'cc', '99' ]

コード006

enum Format {ARRAY = 1, STRING = 2};
console.log(Format);  // { '1': 'ARRAY', '2': 'STRING', ARRAY: 1, STRING: 2 }
function getColorComponents(color: number, format = 0): 
    (number | string)[] |
    {red: number | string, green: number | string, blue: number | string}
{
    let red : number | string = color >> 16;
    let green: number | string = color >> 8 & 0xFF;
    let blue: number | string = color & 0xFF;
    if ((format & 2) === Format.STRING) {
        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);
    }
    if ((format & 1) === Format.ARRAY) {
        return [red, green, blue];
    } else {
        return {red: red, green: green, blue: blue};
    }
}

07 Union型に名前をつける

前掲コード006では、数値(number)か文字(string)という型づけがあちこちで使われています。型の別名(type alias)を用いると、ひとつの名前でまとめてしまえます。以下のコード007のようにわかりやすい名前にすれば、スクリプトも見やすくなります。なお、配列はジェネリック型で定めました(別の書き方を示しただけですので、とくに大きな違いはありません)。

コード007

enum Format {ARRAY = 1, STRING = 2};
type NumberOrString = number | string;
console.log(Format);  // { '1': 'ARRAY', '2': 'STRING', ARRAY: 1, STRING: 2 }
function getColorComponents(color: number, format = 0): 
    Array<NumberOrString> |
    {red: NumberOrString, green: NumberOrString, blue: NumberOrString}
{
    let red : NumberOrString = color >> 16;
    let green: NumberOrString = color >> 8 & 0xFF;
    let blue: NumberOrString = color & 0xFF;
    if ((format & 2) === Format.STRING) {
        red = red.toString(16);
        green = green.toString(16);
        blue = blue.toString(16);
    }
    if ((format & 1) === Format.ARRAY) {
        return [red, green, blue];
    } else {
        return {red: red, green: green, blue: blue};
    }
}
FumioNonaka
はなし家、もの書き、コード書き。詳しくはwebで。 担当講座: 電気通信大学ウェブシステムデザインプログラム「Web UI・UXプログラミング演習I・Ⅱ」 https://www.websys.edu.uec.ac.jp/ ロクナナワークショップ「Vue.js入門講座」 https://67.org/ws/workshop/detail/0136javascript.html
http://www.fumiononaka.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした