Union

TUどちらでも扱えるときに間に|を挟んでT | Uという感じで記述します。飲む関数の場合Water | Curryどちらも成り立つというような感じです。

Union の例

以下はNumberでキャストするのでstringnumberどちらでも大丈夫です。

const onePlus = (num: string | number) => Number(num) + 1;
console.log(onePlus('1')); // 2

次もそれぞれに存在するプロパティを使うので大丈夫な関数です。

interface Value {
  value: number;
}

interface Foo extends Value {
  foo: any;
}

interface Bar extends Value {
  bar: any;
}

const onePlus = (value: Foo | Bar) => value.value + 1;

JavaScript 構文で絞り込み

次のコードはstring | string[]を受け取って必ずstring[]で返したい関数です。つまりstringだった時は配列に変換してあげる必要があります。 こういう時に使うのがtypeofArray.isArrayです。TypeScriptは賢いのでこの辺りを使うと型を絞り込んでくれます。

const ensureArray = (value: string | string[]) => {
  if (typeof value === 'string') {
    // ここで`value`は`string`型
    value = [value];
  }
  // または `!Array.isArray(value)`を使う
  return value;
}

他に型の絞り込みに使えるもので

  • instanceof
  • in
    • 例えば 'foo' in valueFooに絞込

があります。

複雑な絞り込みは Type Guards を使う

複雑な絞り込みの時はType Guardsを使うとスッキリします。これにはarg is Tという奇妙な戻り値を返すようにします。
例えば以下のisFooは値のtype: 'foo'hogeプロパティを持ってたらFooということにしてる関数です。

interface Foo {
  type: 'foo';
  hoge: string;
}

interface Bar {
  type: 'bar';
  fuga: string;
}

function isFoo(arg: Foo | Bar): arg is Foo {
  return (
    arg.type === 'foo' && Object.prototype.hasOwnProperty.call(arg, 'hoge')
  );
}

// モック
const arg: Foo | Bar = undefined as any;
if (isFoo(arg)) {
  // ここで`arg`は`Foo`型
  console.log(arg.hoge);
}