1
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?

More than 1 year has passed since last update.

食わず嫌いを克服したい:TypeScriptで苦手なところだけかいつまんでやってみた②

Last updated at Posted at 2022-12-15

はじめに

TypeScript、難しいですよね(少なくとも私は得意ではありません)? 特に抽象度が高くなるとすぐに脳内メモリが足りなくなるので、なんとなくの実装で乗り切ってきたのですが...。そうこうも言ってられなくなったので(遅い)、曖昧なところを潰してみることにしました。

▼前回の記事はこちら
https://qiita.com/sazumy/private/7c4f35500aa51210a4d4

使用テキスト

使用したのはこちらのテキスト。コードもこちらの書籍から引用しています。全てのコードには該当ページ数も書いておきます。

ユニオン型

まずはユニオン型です。ユニオン型は「TまたはU」という状態を表す方で、T | Uと書きます。具体例はこんな感じです。AnimalまたはHumanの型を持つUserという方は、以下のような事例に使うことができます。

type Animal = {
  species: string;
}

type Human = {
  name: string;
}

type User = Animal | Human;

// User型はnameまたはspeciesのプロパティを持つので、これはコンパイルが通る
const tama: User = {
  species: "cats"
}

// これもコンパイルが通る
const firstUser: User = {
  name: "taro"
}

// titleというプロパティはUser型にないので、これはコンパイルエラー
const book: User = {
  title: "The Tale of Peter Rabbit"
}

// これもコンパイルが通る???
const pochi: User = {
  species: "dogs",
  name: "pochi"
}

プロを目指す人のためのTypeScript入門:p.248のコードを改変して使用

解せないのは、speciesnameの両方のプロパティを持つ、以下のオプジェクトもコンパイルが通ってしまうこと。

const pochi: User = {
  species: "dogs",
  name: "pochi"
}

TかつUという型を作るのは、この記事の下方で挙げているインターセクション型の役割じゃなかったっけ?
...結局この点については解消しなかったのですが、暫定的に上記の時点では、pochiAnimalであるかHumanであるか確定していないからという結論になりました。誰か正しい答え知っていたら教えてください...

なお、ユニオン型は下記のように書くことも可能です。

type User =
    | Animal
    | Human

実務のコードで時々見ますが、そういう意味だったのかと改めて確認:relaxed:

インターセクション型

インターセクション型は「TかつU」を表す型で、T & Uと書きます。そして、オブジェクト型を拡張する新しい型を作ります。
具体例は以下のようになります。

type Animal = {
  species: string
}

type Human = {
  name: string
}

type User = Animal & Human;

const pochi: User = {
  species: "dogs",
  name: "taro"
}

// こんな風にオブジェクト型ベタ書きでも型を拡張できる
type AnimalWithAge = Animal & { age: number };

const tama: AnimalWithAge = {
  species: "dogs",
  age: 5
}

プロを目指す人のためのTypeScript入門:p.253のコードを改変して使用

こちらはとても簡単ですね:relaxed:
個人的には Animal & { age: number }みたいに、オブジェクトの型 & オブジェクトの型のベタ書きで拡張できるのがよかったです。色々柔軟に考えられそう。

ユニオン型とインターセクション型の練習

頭の体操的な記載も一つ載っていたので試してみることにしました。
このような、Human型のオブジェクトを受け取ったらnameを、Animal型のオブジェクトを受け取ったらspeciesを返すメソッドを作ってみました。

const tama: Animal = {
  species: "cats"
}
const firstUser: Human = {
  name: "taro"
}

const getName = (human: Human) => {
  return human.name;
}
const getSpecies = (animal: Animal) => {
  return animal.species;
}
// randomFuncは、const randomFunc: ((human: Human) => string) | ((animal: Animal) => string) というユニオン型
const randomFunc = Math.random() < 0.5 ? getName : getSpecies

// ここでコンパイルエラーになる
randomFunc(tama)
randomFunc(firstUser)

プロを目指す人のためのTypeScript入門:p.255のコードに追記して使用

randomFunc((human: Human) => string) | ((animal: Animal) => string)というユニオン型ですが、呼び出す際にHuman型かAnimal型のどちらかのオブジェクトを入れて呼び出すとエラーになります。

そこで、tamafirstUserHuman & Animal型である以下の型を適用。

// ここをHuman & Animal型に
const tama: Human & Animal = {
  name: "tama",
  species: "cats"
}
// ここもHuman & Animal型に
const firstUser: Human & Animal = {
  name: "taro",
  species: "human"
}

const getName = (human: Human) => {
  return human.name;
}
const getSpecies = (animal: Animal) => {
  return animal.species;
}

const randomFunc = Math.random() < 0.5 ? getName : getSpecies
// コンパイルエラーが出ない
randomFunc(tama)
randomFunc(firstUser)

プロを目指す人のためのTypeScript入門:p.256のコードに追記して使用

無事、エラーなく呼び出せました:relaxed:

感想

TypeScript...今でも苦手意識強いのですが、一つ一つ読み解いていくことで何とか実務でも落ち着いて取り組めそうです。
アドベントカレンダーという機会があってやってみてよかったです。

1
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
1
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?