Slide 1

Slide 1 text

TypeScriptで Vueを書いてみよう! Vue/Nuxt meetup #7 Daiki Kojima (@Daikids2)

Slide 2

Slide 2 text

https://speakerdeck.com/daikids2/typescriptde-vuewoshu-itemiyou

Slide 3

Slide 3 text

⼩島⼤基 (Daiki Kojima) • Student@京⼤院(情報学) • Twitter: @Daikids2 • GitHub: daikikojima

Slide 4

Slide 4 text

Index • What is TypeScript • TSでコンポーネントを書いてみる • VuexでもTSを書いてみる • まとめ

Slide 5

Slide 5 text

What is TypeScript

Slide 6

Slide 6 text

About TypeScript • Microsoftが開発したAltJSの⼀種 • ES5のスーパーセット • 型とか、ClassとかInterfaceが使える

Slide 7

Slide 7 text

型が使えてうれしいこと… • JSだとこのまま実⾏されてしまう。 • 予期せぬバグの原因に • ちなみに… • add(a,b) -> 11 (string型) • mul(a,b) -> 1 (number型) function add (a, b) { return a + b; } function mul (a, b) { return a * b; } const a = 1; const b = “1"; add(a, b); mul(a, b);

Slide 8

Slide 8 text

TSだとこう書ける! • トランスパイルの段階で はじかれるし、 VS Codeとかだと、書くだけで 怒られる function add(a: number, b: number): number { return a + b; } function mul(a: number, b: number): number { return a * b; } const a = 1; const b = "1"; console.log(add(a, b)); console.log(mul(a, b));

Slide 9

Slide 9 text

Interfaceが使えるぞ!! • (僕的には)TS使う⼀番の理由だったりする… • Object内のプロパティとその型を記述したもの • こんなやつです↓ export default interface Todo { content: string; status: number; key: string; }

Slide 10

Slide 10 text

JSDocとの違い • JSDocは何回も書く必要あり? • TSなら⼀度どっかに書いとけばそれをimportするだけでいい • entities/*.tsとか、models/*.tsとか /** * @param todo TODO Entity Object * @param {string} todo.content actual task * @param {number} todo.status status: {todo->0, doing->1, done->2} * @param {string} todo.key firebase key */ export default interface Todo { content: string; status: number; key: string; }

Slide 11

Slide 11 text

TSでComponentを書いてみる

Slide 12

Slide 12 text

気になったら… • https://github.com/daikikojima/Open-CharTo に実際に動かしているコードがあります。

Slide 13

Slide 13 text

その前に… • Vue cliのバージョンは3以上 • @vue/cliを使う • vue-cliはもうdeprecated • Nuxtの場合はまだ知らないです…

Slide 14

Slide 14 text

Creating project • 思考停⽌してもできます!

Slide 15

Slide 15 text

Class Style Componentって? import Vue from 'vue'; import {mapGetters, mapActions, mapState} from 'vuex'; export default Vue.extend({ name: 'Header’, props: { isToggled: { type: Boolean, required: true, }, doLogout: { type: Function, required: true, }, toggleBurger: { type: Function, required: true, }, }, computed: { ...mapGetters( ['isLoggedIn’], ), }, }); 普通に書いた場合 (Object Style)

Slide 16

Slide 16 text

Class Style Componentって? import {Component, Prop, Vue} from "vue-property-decorator"; import {mapGetters, mapActions, mapState} from 'vuex'; @Component({ computed: { ...mapGetters( ['isLoggedIn’], ), }, }) export default class Header extends Vue { @Prop() private isToggled!:boolean; @Prop() private doLogout!:() => {}; @Prop() private toggleBurger!:() => {}; } 型周りはきれい

Slide 17

Slide 17 text

実は… https://github.com/vuejs/rfcs/pull/17#issuecomment-494242121

Slide 18

Slide 18 text

RFCでは採⽤されないことに… • Rfc上でdropされました… • エッジケース・仕様依存・未解決の問題があるため • composition functionsのほうがいい ってEvan Youが⾔ってました… • 未だに@vue/cliでは使うに決まってるよね、 と聞かれます

Slide 19

Slide 19 text

VuexもTSで書いてみる

Slide 20

Slide 20 text

Vuexってなんだっけ… • FluxをVueで簡単にやろうぜ! っていうやつ • Vuejsが管理しているように、 Vueで簡単に扱えるように作られている。

Slide 21

Slide 21 text

公式の画像やけど… https://vuex.vuejs.org/ja/

Slide 22

Slide 22 text

そのまえに… Page固有の Store Root Store • 基本的にこんな感じで ディレクトリ構成を考える

Slide 23

Slide 23 text

Actions • VueからActionを受け取る部分 • この中にどんどんactionを定義していく const actions: ActionTree = {... initialize({ commit }) { const user = this.state.user; if (user !== null) { firebaseRdbService.getTodos(user, (todos: TodoResponse|null) => { if (todos !== null) { commit('setTodos', objModule.objectToArrayWithKey(todos!)); } }); } },

Slide 24

Slide 24 text

もし、RootStateを定義しない場合… • Anyで逃げてください • 特に、Reducksパターンとか、ページごとにStateが独⽴なら こうなることがあるかも! const actions: ActionTree

Slide 25

Slide 25 text

Mutations • めっちゃかんたん • ここでも引数に型、つけられます! const mutations: MutationTree = {... const mutations: MutationTree = { setTodos(state: TopState, todos: Todo[]): void { state.todos = todos; }, };

Slide 26

Slide 26 text

Getters • これもかんたん! • 普通のTypeScriptですよね… const getters: GetterTree = {... const getters: GetterTree = { getAllTodos(state: TopState): TodoPacks|null { return { todo: filterTodos(state.todos, 0), doing: filterTodos(state.todos, 1), done: filterTodos(state.todos, 2), }; }, ...

Slide 27

Slide 27 text

こうすると嬉しかったこと… • どこからどんなobjectが来るかが明⽰的にわかる! • いったんtypesとか、modelsみたいなとこに書いとけば それを参照するだけでいい! • 実際にはentitiesディレクトリを作ってそこにinterfaceは書いてます

Slide 28

Slide 28 text

ただし…

Slide 29

Slide 29 text

当然⾟い部分も出てくる…

Slide 30

Slide 30 text

(個⼈的に)⾟かった部分 • Router部分のGuardの引数とか… • 参考してたサイトに従って型定義したけどダメ • (いま書いたりしてるけど)テストとか… • wrapper.vmにpropとかdataがないと⾔いやがる注意してくれる…

Slide 31

Slide 31 text

解決策

Slide 32

Slide 32 text

Anyを使おう!! • そもそもここら辺ってあんま厳密な型はいらなそう • テストなんて動いてくれればいいでしょ (正論)

Slide 33

Slide 33 text

Anyが恥ずかしいと思う⽅へ… https://twitter.com/__gfx__/status/1127816243040227330

Slide 34

Slide 34 text

Anyは恥ずかしいくない!! • 確かに、Vue + TSは厳密にやろうとすると⾟い… •でも、使えるとこだけうまいことつかおうや?

Slide 35

Slide 35 text

まとめ • VueもTSで書く時代です。 • Componentを書くのはつらいかもしれない • Vuexはわりかし書きやすい •Anyは恥じゃない!!