デザインからTypeScriptと仲良くなってみる。

自己紹介

業務委託でestieに参画している@HirokiOmoteです。

estieでは主にデザインとFrontendを担当しています。
過去には、スタートアップの創業フェーズでプロダクトの立ち上げなども行なっていました。
そこでは、Nuxt + Firebaseを採用し、Webアプリの制作に着手。
しかし、プロダクトが成長するにつれ、コードの安全性や可読性の観点からJavaScript…動的型付け言語の限界を感じていました。

そして、静的型付け言語であるTypeScriptを採用することに。
また、Firebase Cloud Functionsを使った機能開発も行うようになり、次第にBackendもTypeScriptを使って書くようになりました。

それが、TypeScriptとの出会いです。
気づけば、すっかりその魅力に取りつかれていました。TypeScriptは楽しい。

そもそもTypeScriptとは

「Type」と名のつくように、Type=型によるチェックが可能です。
そのため、プログラムの可読性の向上やバグの発見が容易になるため、リリース前後の修正コストを抑えることができます。

Airbnbでは、TypeScriptを採用後、38%ものバグを未然に防ぐことができたとか。
TypeScriptはMicrosoftによって開発されたオープンソース言語であり、Visual Studio Codeによる補完がよく効くのも快適な開発体験の一助になっています。

また、TypeScriptはJavaScriptの最新仕様が使える上方互換(スーパーセット)でもあるので、型について深く知らなくても、モダンなJavaScriptの書き味を体験できるという点だけで、面白さがあるのではないでしょうか。(optional chainingとか)
型推論もありますし、JavaScriptとそう変わらないコード量になることも多いですね。

ReactやVueなどのモダン・フロントエンドでも、TypeScriptの親和性は年々高まっていますが、DenoやNode.js(ts-node)でも対応しているため、BackendでもTypeScriptを採用するケースが増えているようにも感じます。Next.jsやNuxtならTypeScriptだけでフルスタックに作っていけますね。

現在、TypeScriptの人気は4位。estieで採用されているRustも人気を上げてますねー!

どんな時に使うか

主に以下の様なメリットを感じています。

  • リアルタイムでエラーを指摘してくれる(Visual Studio Code)
  • Componentでpropsの中身がわかりやすい

もちろん、estieでもFrontendではTypeScriptの導入を積極的に行なっています! estieではReact、Vueのどちらも採用されていますが、今回はReactを軸に解説していきたいと思います。

Figmaでのボタンのデザイン例

FigmaでAtomicButtonというコンポーネントを作りました。
primary secondary danger の3種類の出し分けができるように、Propertiesを設定。
これらをReactでコーディングします。CSSは割愛。

JavaScript(JSX)
import React from "react";

export default function AtomicButton(props) {
  return (
    <div className={ props.type || 'primary' }>
      <button disabled={ props.disabled }>{ props.text }</button>
    </div>
  )
}

propsに何が入ってくるのか分かりません。

そのため、AtomicButtonというコンポーネントにどんな機能があるか把握しにくいですね。
タイプミスで不用意にprops.hogeにアクセスして、undefined が返されるケースもありそうです。 心臓に悪いです…。

TypeScriptで型をつけてみる

いよいよTypeScriptに挑戦です! 簡単に型をつけてみましょう。

今回、大事なのはFigmaで設計したPropertyをtype Propsとして再現することです。

TypeScript(TSX)
import React from "react";

type Props = {
  text: string // Buttonテキスト
  disabled?: boolean // Disabled属性を付与
  mode?: 'primary' | 'secondary' | 'danger' // ボタンの種類の出しわけ
}

export default function AtomicButton(props: Props) {
  return (
    <div className={ props.type || 'primary' }>
      <button disabled={ props.disabled }>{ props.text }</button>
    </div>
  )
}

型を明示するだけで、textmodeの役割が少し明るくなりました。
textの型はあらゆる文字列が入力できるstring型に指定します。
modeの型ははUnion型と言います。'primary' | 'secondary' |  'danger'のいずれかの文字が入ってくることを示しています。

disabledはboolean型で、<button>タグにdisabled属性をつけられるようにもしています。

また、type?disabled?はoptional型で省略可能を示しています。
こうすることで、コンポーネントを<button>の挙動と同じになる様に拡張することもできますね。

特にAtomic Designでは、Atomsの様に小さく汎用的なコンポーネントほど多機能になり、Propsが肥大していくこともしばしば。 プロダクトによっては、その数が30を超えるケースもあるそうです。
だからこそ、Figma・TypeScript間での設計はかなり重要です。
逆に言えば、役割が整然されたデザインは、プロダクトや会社にとっての資産になり得ると考えています。

一貫性のあるものは美しいですね。

最後に型クイズ

前項でもお伝えしましたが、TypeScriptはJavaScriptのスーパーセットであるので、型も必要最低限の知識で十分使っていけます。

とはいえ、 複雑なstateの設定や関数を作成する際、上手く設計や型がハマった場合に、とても気持ちがいいです。

それではここでクイズ。 ???を満たすTypeを探してみましょう!

Q1

export const q1 : A1 = 'text1'
export const q1_2 : A1 = 1

type A1 = ???

Q2

const q3 = (value : A3) => {
  console.log(`${value} World!`)
}

q3('Hello')
q3('GoodBye')
q3('Seeyo') // compile error

type A3 = = ???

Q3

export const q4 : A6 = 'text'
export const q5 : A6 = 1
export const q6 : A6 = true

type Union<T, U> = T | U
type A4 = ???
type A5 = ???
type A6 = Union<???>

Q4

type stringArray = ['first', 'middle', 'second']
type numberArray = [1, 2, 3]

type stringFirst = First<stringArray> // firstを返す
type number2 = First<numberArray> // 2を返す

type First<T> = ???

まとめ

  • TypeScriptはモダンJavaScriptに型をつけたもの
  • コンポーネントの状態管理(state)だけでも使っていける
  • パズルゲーム的な面白さもある

最後までご覧下さいまして、ありがとうございました!
estieはデザイン~エンジニアリングの垣根を超えて働ける場所で、とても楽しいです。
興味をお持ちの方は、デザイン、Frontend、Backend問わず、ぜひお話ししましょうー! (もちろん答え合わせも!)

Twitterからも、是非、ご連絡ください。 表洋樹 / estie (@HirokiOmote) / Twitter

またはこちらから!

hrmos.co

© 2019- estie, inc.