Slide 1

Slide 1 text

Nuxt+TypeScript 事始め #NuxtMeetup @sue71 2018/05/15

Slide 2

Slide 2 text

自己紹介 Masaki Sueda github: sue71 twitter: @sue__71 Merpay web フロントエンド/iOS ソリューションチーム 便利屋 技術課題を解決する人

Slide 3

Slide 3 text

今日話すこと Vue プロジェクトのTypeScript 対応状況や相性 Nuxt+TypeScript の対応方法 Vue Vuex Nuxt

Slide 4

Slide 4 text

TypeScript?

Slide 5

Slide 5 text

TypeScript の特徴 静的型付け言語でJavascript が書ける 型定義による型の後付け

Slide 6

Slide 6 text

TypeScript のメリット Type Safe Less test / documentation

Slide 7

Slide 7 text

Vue プロジェクトの型定義状況 コンポーネント 対応状況 備考 vue ◯ ver 2.5=> で改善 vue-template ✕ 型解析されない vuex △ 型定義はあるが... nuxt ✕ 型定義がない

Slide 8

Slide 8 text

環境構築

Slide 9

Slide 9 text

IDE VSCode Typescript 補完バッチリ Vetor for VSCode Vue 公式プラグイン Language-Service-Protocol 準拠 Vue ファイルの補完

Slide 10

Slide 10 text

Lint eslint-plugin-vue を使いたい -> eslint TypeScript -> typescript-eslint-parser で対応 Interface などがlint に引っかかる場合があるので幾 つかルールをOFF にする no-unused-vars no-undef

Slide 11

Slide 11 text

Vue + TypeScript

Slide 12

Slide 12 text

Vue Component v2.5 からComponentOption 形式に対応 tscon g にてnoImplicitThis をtrue に ⇢ 暗黙的なthis へのマッピングを解決 Vue.extend({ data() { return { hoge: 0 } }, computed: { foo(): string { return this.hoge; // Error } } });

Slide 13

Slide 13 text

Vue Stateless Component template のみのファイルを読み込むためのtweak declare module "*.vue" { import Vue from "vue"; export default Vue }

Slide 14

Slide 14 text

hello.vue
Hello
hello-container.vue import Vue from "vue"; import hello from "hello.vue"; export default Vue.extend({ components: { hello } })

Slide 15

Slide 15 text

Vue-Plugin Vue にインジェクトされるもの型を定義する $store, $router, etc... VueComponentOption に提供されるメソッドの型 を定義する

Slide 16

Slide 16 text

Vuex-Store declare module "vue/types/options" { interface ComponentOptions { store?: Store; } } declare module "vue/types/vue" { interface Vue { $store: Store; } }

Slide 17

Slide 17 text

Vuex + TypeScript

Slide 18

Slide 18 text

Vuex データフローは最も重要な部分 → TypeSafe に書きたい 型定義はあるがany で定義されるものが多い → TypeSafe じゃない

Slide 19

Slide 19 text

型定義ファイル type MutationTree = { [key: string]: ( state: State, payload: any, rootState: RootState ) => void } 実装 const mutations: MutationTree<{}, {}> = { increment(state, payload /*any*/) { } };

Slide 20

Slide 20 text

型定義を改善する TypeScript2.1 から提供されているMappedType を 利用 → キーと引数の型の組み合わせが定義できる

Slide 21

Slide 21 text

追加の型パラメータ type Couter = { increment: number; } 改善した型定義 type MutationTree = { [K keyof Mutations]: ( state: State, payload: Mutations[K] /*Counter[increment]*/, rootState: RootState ) => void }

Slide 22

Slide 22 text

実装 const mutation: MutationTree<{}, {}, Counter> = { increment(state, payload /*number*/) { state.count = payload } }

Slide 23

Slide 23 text

Actions dispatch やcommit の定義もtypesafe にできる const actions: ActionTree<..., CouterA, CounterM> = { increment(context, payload) { context.commit("increment", "hoge"); // Error context.commit("incremento", 1) // Error } }

Slide 24

Slide 24 text

TypeSafe ではあるが、、 実装と一致しないInterface を定義する気持ち悪さ は残る namespaced ではない場合さらに型パラメーターを 渡さなければならない

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Nuxt + Typescript

Slide 27

Slide 27 text

NuxtContext Nuxt から提供されるコンテキストAPI export interface NuxtContext { app: Vue; isClient: boolean; isServer: boolean; isStatic: boolean; // ... beforeNuxtRender: Function; } 参照: https://nuxtjs.org/api/context/

Slide 28

Slide 28 text

nuxtServerInit declare module 'vuex/types/index' { interface ActionTree { nuxtServerInit?: (..., context: NuxtContext) => void; } }

Slide 29

Slide 29 text

Pages /pages 配下のコンポーネントに対して与えられる 拡張 interface PageComponentOptions { layout?: string | (ctx: NuxtContext) => string; ... middleware?: string | string[] }

Slide 30

Slide 30 text

まとめ

Slide 31

Slide 31 text

Vue プロジェクトでTypeScript 採用するなら型定義 書くくらいの気持ちは必要 完全にTypeSafe に書きたいならAngular, React を推 奨 Nuxt みたいに機能の多いAPI を覚えるのは大変 定義があるとAPI にどこで何ができるかすぐ分か るしプロジェクトの皆で共有できる → 取り敢えずTypeScript 使っていきましょう

Slide 32

Slide 32 text

ご清聴ありがとうございました。