Techtouch Developers Blog

テックタッチ株式会社の開発チームによるテックブログです

TypeScript 4.1 に更新しました

adventCalendar-day2

この記事はテックタッチアドベントカレンダー2日目の記事です。 1日目は mistyによる Postman をチームで運用していくためにフォーク機能を使ってみた でした。

フロントエンドエンジニアの国定です。久しぶりにポケモンで遊び始めたのですが、PokemonHOME というマルチプラットフォームのクラウドサービスでポケモンを一元管理できるようになってて感動しました。

テックタッチで使っている TypeScript を3.9から4.1に更新したので、影響の大きそうな変更を紹介します。

Template Literal Types

JavaScript では既に Template literals が使えますが、それに近しいことを型で表現できるようになりました。

// tempalate literal (JS)
const world = 'world'
console.log(`hello ${world}`) // hello world

// template literal types
type World = 'world'
type Greeting = `hello ${World}`
// type Greeting = 'hello world' と同義

テックタッチではこのような使い方をしています

type DisplayDateFormat = `${string}/${string}/${string}`
const date: DisplayDateFormat = '20201202' // エラーになる
const date: DisplayDateFormat = '2020/12/02'

// type PlayerIconPosition = 'left_middle' | 'left_bottom' | 'right_middle' | 'right_bottom' と同義
type PlayerIconPosition = `${'left' | 'right'}_${'middle' | 'bottom'}`

型レベルで文字列のフォーマットを定義できるので、上手に使えばフォーマットの検証を TypeScript に任せることもできちゃいますね。

Checked Indexed Accesses

配列やindex signatureを使ったオブジェクトなど、値が存在するかわからないIndexアクセスの場合に undefined の可能性があるよと教えてくれるようになりました。 tsconfig.json に "noUncheckedIndexedAccess": true, を追加してこの機能を有効にできます。

type Props = {
  [key: string]: string 
}
function toLower(props: Props) {
  // string | undefined なので代入できない
  const hoge: string = props['test']
}

const array: string[] = []
for(let i=0; i<array.length; i++) {
  // string | undefined なので代入できない
  const data: string = array[i]
}

有効にしてみたものの修正が多く、それぞれ適切な例外処理を考える必要があったので実際に有効にするのはまだ時間がかかりそうです。例外処理考えてると関数が例外を投げることが上層に伝わる機能が欲しくなりますね。。

Promise.resolve の引数が Optional ではなくなった

明示的に型の指定が必要になったため、Promise をより型安全に使うことができます。

// TypeScript4.1 では resolveの引数を指定しないとエラーになる
new Promise((resolve) => {
  doSomethingAsync(() => {
    resolve() // Expected 1 arguments, but got 0.
  })
})

// resolveのパラメータを使わない場合はvoidを指定する
new Promise<void>((resolve) => {
  doSomethingAsync(() => {
    resolve()
  })
})

any/unknown Are Propagated in Falsy Positions

4.0以前はこのような関数の返り値の型は boolean になっていましたが4.1では any を返すようになります。 4.1にアップデートすると気づかない内に any を返す関数になってしまっていることがあるかもしれないので、注意する必要がありそうです。

// 4.1 では function isEnabled(obj: any): any と解釈される
function isEnable(obj: any) {
  return obj && obj.enable === true
}

// booleanであることを明記するか!!objとすることで返り値の型をbooleanにする
function isEnable(obj: any): boolean {
  return !!obj && obj.enable === true
}

明日はtaisaによる GORM v2 のお話です。みんなちゃんと更新してて偉い!