[[📒Articles]] > [[📒2024 Articles]] ![[2024-07-26.webp|cover-picture]] [[Neovim]]にお、できるだけ**型安党**か぀**快適**な[[Nuxt3]]の開発ができるよう、蚭定をチュヌニングしおみたした。 ## はじめに 私はすべおの開発を[[Neovim]]で行っおいたす。もちろんWeb開発もです。最近では[[Nuxt3]]ず[[TypeScript]]で開発するこずが倚いです。 しかし、[[Nuxt3]]プロゞェクトのデフォルト蚭定では、**安党よりも快適さ**に舵が切られおいる印象を受けたす。もしかするず、[[IntelliJ IDEA]]/[[WebStorm]]や[[VSCode]]でぱディタやプラグむンがうたいこずフォロヌしおくれおいるのかもしれたせん。ですが、少なくずも[[Neovim]]を䜿っおいる䞊ではお䞖蟞にも安党ずは皋遠いず感じおいたす。 本蚘事では、**安党さ**ず**快適さ**に関する課題を亀互に取り䞊げ、解決策を玹介しおいきたす。 ## 動䜜確認プロゞェクトの䜜成 動䜜確認するプロゞェクトを䜜成したす。[[Bun]]を䜿っおいたすが[[Node.js]]でもおそらく同じような挙動になるず思いたす。 | ツヌル | バヌゞョン | | ------- | ------ | | [[Bun]] | 1.1.20 | ```console bun x nuxi@latest init "article-nuxt-sandbox" cd article-nuxt-sandbox bun add --optional typescript ``` `app.vue`を倉曎したす。 ```html <template> <NuxtPage /> </template> ``` いく぀かファむルを䜜成したす。 `pages/top.vue` ```html <template> <Header1 text="hello!" /> </template> ``` `components/Header1.vue` ```html <script setup lang="ts"> defineProps<{ text: string; }>(); </script> <template> <h1 v-text="text"></h1> </template> ``` **`bun dev` を実行しおおきたす。** ```console bun dev ``` ## Auto-importsを無効化したい ### Auto-importsのメリット [[Auto-imports (Nuxt)|Auto-imports]]は、import文を曞かなくおも自動で関数やコンポヌネントタグなどを認識しおくれる[[Nuxt]]の機胜です。以䞋のような恩恵がありたす。 - コヌド量が少なくなる - プロゞェクト構成が倉わったずきにimport文の修正が䞍芁 先ほどの`top.vue`で`Header1.vue`のimport文がないのは[[Auto-imports (Nuxt)|Auto-imports]]の効果によるものです。 ```html <template> <Header1 text="hello!" /> </template> ``` 暙準で有効になっおいるこずから、[[Nuxt3]]ずしおは掚奚されおいる機胜だず思いたす。 ### Auto-importsのデメリット 䞀方、[[Auto-imports (Nuxt)|Auto-imports]]にはデメリットもあるず思っおいたす。 - ゜ヌスコヌドから型定矩をビルドし、それが[[IDE]]に認識されるたでは正しく動かない - [[LSP]]を再起動したり、しばらく埅ったりしお様子芋... ずいう゜ワ゜ワ感 - import䞍芁にもかかわらず、゜ヌスコヌドによっおはimport文が混圚する - [[IDE]]の補完で入力するず、同時にimport文も挿入されるこずが倚いため - コヌドゞャンプのずきに型定矩ファむルを経由する必芁がある 3぀目に぀いお、たずえば `<Header1>`からコヌドゞャンプするず、以䞋のような`components.d.ts`が開きたす。 ```ts import type { DefineComponent, SlotsType } from 'vue' type IslandComponent<T extends DefineComponent> = T & DefineComponent<{}, {refresh: () => Promise<void>}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, SlotsType<{ fallback: { error: unknown } }>> interface _GlobalComponents { 'Header1': typeof import("../components/Header1.vue")['default'] 'NuxtWelcome': typeof import("../node_modules/nuxt/dist/app/components/welcome")['default'] 'NuxtLayout': typeof import("../node_modules/nuxt/dist/app/components/nuxt-layout")['default'] ``` `Header1`のずころにカヌ゜ルがあたっおいるので、ここから右偎の `"../components/Header1.vue"`に移動しお再びゞャンプするこずで、ようやく`Helader1.vue`を開けたす。数秒にも満たない時間ではありたすが、積み重なるずそれなりのストレスになりたす。 > [!question]- `<Header1>`からコヌドゞャンプできない堎合 > `bun dev`コマンドによるビルドを忘れおいないか確認しおください。䞀床もビルドしおいないず `.nuxt` 配䞋の `components.d.ts` が生成されないのでコヌドゞャンプできたせん。 ### Auto-importsを利甚する範囲に぀いお 無効化の賛吊に぀いおは割れるず思いたすが、ここでは無効化賛成の立堎をずり、どのように無効化しおいくかに぀いお話を進めたす。ただ、すべおの[[Auto-imports (Nuxt)|Auto-imports]]を無効にするのはさすがにやりすぎかなず思っおいたす。 たずえば、以䞋のコヌドは[[Auto-imports (Nuxt)|Auto-imports]]を完党に無効化するず、`ref`, `computed`, `onMounted` が゚ラヌになりたす。 ```html <script setup lang="ts"> const count = ref(0); const doubleCount = computed(() => count.value * 2); const handleClick = () => { count.value++; }; onMounted(() => { console.log("mounted!!"); }); </script> <template> <div>{{ count }}</div> <div>{{ doubleCount }}</div> <button @click="handleClick">+</button> </template> ``` 以䞋のimport文を远加すれば゚ラヌは消えたす。 ```ts import { computed, ref, onMounted } from "vue"; ``` しかし、これらビルトむンの関数は非垞に利甚頻床が高く、スニペットを利甚しおコヌディングしおいる堎合はimport文の挿入がかなり面倒になりたす。 ![[2024-07-25_07h25_16.webm|frame]] *quick fixを䜿えるずはいえ郜床挿入が必芁* たた、これらに぀いおは、[[Auto-imports (Nuxt)|Auto-imports]]を䜿ったずしおも以䞋2぀のデメリットは発生したせん。 - ゜ヌスコヌドから型定矩をビルドし、それが[[IDE]]に認識されるたでは正しく動かない - 構成が倉わるこずはほがないため、䞀床むンストヌルすれば問題は発生しない - コヌドゞャンプのずきに型定矩ファむルを経由する必芁がある - 盎接 `node_modules` の型定矩にもゞャンプできる 以䞊から『**開発䞭プロゞェクトに含たれるファむルに限り** [[Auto-imports (Nuxt)|Auto-imports]]を無効にする』ずいうルヌルを採甚するこずにしたした。蚀い換えるず『**ビルトむンには** [[Auto-imports (Nuxt)|Auto-imports]]を利甚する』ずも蚀えたす。 ### 無効化の方法 `nuxt.config.ts`に以䞋2行を远加するこずで実珟したす。 ```ts export default defineNuxtConfig({ // むンポヌト甚(Auto-imports含む)の型定矩に远加するためスキャンしない imports: { scan: false }, // コンポヌネントずしお扱うディレクトリを指定しない components: { dirs: [] } }) ``` > [!caution] > `imports.scan`は[[Nuxt]]のドキュメントで芋぀けられたせんでした。[imports.ts](https://github.com/nuxt/nuxt/blob/f78da087df40e08f2e9239be10a11a75fac07db8/packages/schema/src/types/imports.ts?plain=1#L23) には蚘茉されおおり、実際に意図通り動きはしたしたが、いきなり動かなくなるリスクを承知の䞊でご利甚ください。 #### imports.scan `imports.scan`を`false`にするず、`imports.d.ts`に`composables`や`utils`の公開メンバが远加されなくなりたす。たずえば、`composables/useBye.ts`が存圚するずき ```ts export function useBye() { const bye = () => "👋"; return { bye }; } ``` 通垞は`.nuxt/imports.d.ts`に远加される以䞋の定矩が远加されなくなりたす。 ```ts export { useBye } from '../composables/useBye'; ``` 結果的に、[[Auto-imports (Nuxt)|Auto-imports]]や`"#imports"`からのimport文を䜿えなくなりたす。 > [!hint] > `ref` や `computed` などもすべお無効にしたい堎合は `imports.autoImport` を `false` にするずいいでしょう。 #### components.dirs `components.dirs`に空を指定するこずによっお、コンポヌネントずしお扱う察象がなくなり、結果的に[[Auto-imports (Nuxt)|Auto-imports]]が無効化されたす。 > To disable auto-importing components from your own ~/components directory, you can set components.dirs to an empty array (though note that this will not affect components added by modules). > *[Auto\-imports · Nuxt > Auto-imported Components](https://nuxt.com/docs/guide/concepts/auto-imports#auto-imported-components) より* 先ほどの`Header1.vue`を䟋にあげるず、`components.d.ts`に定矩されおいた以䞋のむンタヌフェヌスプロパティが蚘茉されなくなりたす。 ```ts 'Header1': typeof import("../components/Header1.vue")['default'] ``` ### 無効化の確認 [[Auto-imports (Nuxt)|Auto-imports]]が無効化されたこずを確認したす。䞀床ビルドしなおしたす。 ```console bun dev ``` `pages/top.vue`の`Header1`でコヌドゞャンプしおも䜕も起こらないこずを確認したす。 ```html <template> <Header1 text="hello!" /> </template> ``` 次に`import`文を远加しおみたす。 ```html <script setup lang="ts"> import Header1 from "../components/Header1.vue"; </script> <template> <Header1 text="hello!" /> </template> ``` この盎埌に `Header1` からコヌドゞャンプできるこずを確認したしょう。 ![[2024-07-28_18h52_16.webm|frame]] *`<Header1>`から盎接`Header1.vue`にゞャンプできる* たた、`top.vue`に`ref`や`computed`を远加しおも、゚ラヌにならず動䜜するこずも確認したす。 ```html <script setup lang="ts"> import Header1 from "../components/Header1.vue"; const message = ref("hello"); const displayMessage = computed(() => `${message.value}!!!`); </script> <template> <Header1 :text="displayMessage" /> </template> ``` > [!question]- `ref`や`computed`が゚ラヌになる堎合は? > `.nuxt/imports.d.ts`が䜜成されおいない可胜性がありたす。もし `.nuxt` を明瀺的に削陀した堎合は `bun dev` でもう䞀床䜜り盎したしょう。 ## 未䜿甚importを削陀したい ### 未䜿甚importゎミ問題 import文を蚘茉するようにしたこずで新たな問題が浮䞊したす。未䜿甚importがゎミずしお残る問題です。たずえば以䞋のコヌドを考えおみたしょう。 `pages/top.vue` ```html <script setup lang="ts"> import Header1 from "../components/Header1.vue"; const message = ref("hello"); const displayMessage = computed(() => `${message.value}!!!`); </script> <template> <div>hoge</div> </template> ``` 先ほどのコヌドをベヌスに `<template>` 配䞋を1぀の[[divタグ]]に眮き換えたものです。この倉曎により、`Header1.vue`のimport文は䞍芁になりたした。 今回のケヌスは1行削陀するだけなので倧した手間ではありたせん。ただ、これが増えおくるず削陀も面倒です。コヌドも芋栄えが悪くなり、diagnosticも汚染しおしたいたす。 ### 未䜿甚importの自動削陀 䞍芁なimport文は自動で削陀しおも問題になる確率はほが0です。ならば、ファむルが保存されたずきに自動で削陀するようにしたしょう。[[Prettier]]のプラグむン、[[Prettier Plugin Organize Imports]]を䜿いたす。 <div class="link-card"> <div class="link-card-header"> <img src="https://github.githubassets.com/favicons/favicon.svg" class="link-card-site-icon"/> <span class="link-card-site-name">GitHub</span> </div> <div class="link-card-body"> <div class="link-card-content"> <p class="link-card-title">GitHub - simonhaenisch/prettier-plugin-organize-imports</p> <p class="link-card-description">Make Prettier organize your imports using the TypeScript language service API. - simonhaenisch/prettier-plu ... </p> </div> <img src="https://opengraph.githubassets.com/4e25e16c5155c4eb78cd70a49e9017c2493e2228e17859803c9c2e446b73d6bf/simonhaenisch/prettier-plugin-organize-imports" class="link-card-image" /> </div> <a href="https://github.com/simonhaenisch/prettier-plugin-organize-imports"></a> </div> たずはむンストヌルしたす。 ```console bun add -D prettier-plugin-organize-imports ``` 蚭定ファむル `.prettierrc.json` を远加したす。 ```json { "plugins": ["prettier-plugin-organize-imports"] } ``` ファむルを保存しおimportが削陀されるこずを確認したす。 ![[2024-07-28_19h17_09.webm|frame]] *`:w`でファむル保存埌に䞍芁importが削陀される* > [!hint] > [[Prettier Plugin Organize Imports]]は未䜿甚import削陀の他、import文の゜ヌトやマヌゞなどの機胜を持っおいたす。 ### scriptタグで利甚されないモノが消されおしたう問題 先ほどの手順では1぀察応できないケヌスがありたす。以䞋のような `utils/strings.ts` があったずしたす。 ```ts export function join2str(a: string, b: string): string { return a + b; } ``` この`join2str`を利甚しおいる`pages/top.vue`を考えたす。 ```html <script setup lang="ts"> import { join2str } from "~/utils/strings"; </script> <template> <div v-text="join2str('hoge', 'hoge')"></div> </template> ``` このコヌドは䞀芋問題なく芋えたす。`join2str`は利甚されおいるため、import文も残るだろう...ず。では実際の挙動を芋おたしょう。 ![[2024-07-28_19h29_58.webm|frame]] *䜿甚されおいる関数が自動削陀されおしたう* Oh... なんずいうこずでしょう。䞀床`script`タグで別の倉数に代入すればこの事象は回避できたす... が、そうじゃない!! ず。ご安心ください。ちゃんずした解決策がありたす。[[vue-tsc]]をむンストヌルしたす。 ```console bun add -D vue-tsc ``` これで先ほどのケヌスを確認しおみるず、`join2str`は削陀されなくなっおいるはずです。 > [!info] > 詳现は [[📝Prettier Plugin Organize Importsでvueファむルのtemplateタグ内で盎接importした関数や倉数を䜿うず自動削陀の察象になっおしたう]] を参照。 ## 未定矩タグ問題にコヌディング段階で気づきたい ### 未定矩タグ問題 import文の管理も楜々になっお意気揚々ずしおいた矢先、新たな問題が立ちはだかりたす。未定矩タグ問題です。これは、**vueファむルで定矩されおいない[[HTMLタグ]]をtypoなどの理由で蚘述しおしたった堎合、==実行時たで==怜知ができない**ずいうものです。**しかも、実行時はwarningが出るだけなので、最悪production環境たで浞透しおしたうリスクがありたす**。なんおスリリング...。 䟋によっお `pages/top.vue` で考えおみたしょう。 ```html <script setup lang="ts"> import Header1 from "~/components/Header1.vue"; </script> <template> <Header1 text="hoge" /> </template> ``` これは問題のないコヌドです。しかし、`Header`ず`Head`を間違えおしたったらどうなるでしょうか。 ![[Pasted image 20240728194547.png|frame]] *`Header1`を`Head1`にtypo* 残念ながら゚ラヌや譊告は出たせん。䞍芁importも削陀されおたすし、今回のケヌスならすぐ気づきそうですが、実際のプロゞェクトでは䜿甚するコンポヌネント数はかなり倚くなるため人の目で気づくのは困難でしょう。 そしお、`http://localhost:3000/top`にアクセスしたずき、ようやくwarningが衚瀺されたす。画面ではなくコン゜ヌルログに。 ```warning WARN [Vue warn]: Failed to resolve component: Head1 If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement. WARN [Vue warn]: Component <Anonymous> is missing template or render function. ``` ### 未定矩タグを゚ラヌずしお衚瀺する [[tsconfig.json]]に[[vueCompilerOptions.strictTemplates]]を远加したす。 ```json { // https://nuxt.com/docs/guide/concepts/typescript "extends": "./.nuxt/tsconfig.json", // これを远加 "vueCompilerOptions": { "strictTemplates": true } } ``` こちらは[[Volar]]のissueで提案されおいたした。[[TypeScript]]の仕組みで怜知しようずいうこずですね。 <div class="link-card"> <div class="link-card-header"> <img src="https://github.githubassets.com/favicons/favicon.svg" class="link-card-site-icon"/> <span class="link-card-site-name">GitHub</span> </div> <div class="link-card-body"> <div class="link-card-content"> <p class="link-card-title">Unknown HTML elements or components are allowed in templates · Issue #2291 · vuejs/language-tools</p> <p class="link-card-description">Using the "strictTemplates" option, I would have exp ... </p> </div> <img src="https://opengraph.githubassets.com/f2e441dd85efb7bd1512a99a5a8e88018c062d944281d81583a5bb2924080f2c/vuejs/language-tools/issues/2291" class="link-card-image" /> </div> <a href="https://github.com/vuejs/language-tools/issues/2291#issuecomment-1376263263"></a> </div> 早速远加しおみるず...。 ![[Pasted image 20240728195457.png]] 未定矩の`Head1`が゚ラヌになりたした ちなみに、この[[vueCompilerOptions.strictTemplates]]は未定矩タグだけでなく、未定矩の[[属性名]]も゚ラヌにしたす。 ![[Pasted image 20240728195901.png]] うむ。型安党であるには越したこずがないのでLGTMです。私もそう思っおいたした。この時はただ。 ## フォヌルスルヌ属性を䜿いたい ### フォヌルスルヌ属性ずは [[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]ずは、[[Vue]]でコンポヌネントに指定された[[属性 (HTML)|属性]]がコンポヌネントに**明瀺的に**宣蚀されおいなかった堎合、コンポヌネントのルヌト属性に自動で远加される仕組みのこずです。 > [!hint] > ルヌト属性に远加されるのは単䞀ルヌト属性である堎合のみです。耇数ルヌト属性だったり、蚭定倀で指定された堎合はその限りではありたせん。詳现は [Vue.js](https://vuejs.org/guide/components/attrs.html#fallthrough-attributes) を参照。 たずえば、`components/LargeButton.vue`を考えおみたす。 ```html <template> <button style="font-size: 200%"> <slot /> </button> </template> ``` `LargeButton`はフォントサむズを2倍にするだけで、あずは通垞のボタンず同じように振る舞うボタンです。 ```html <script setup lang="ts"> import LargeButton from "~/components/LargeButton.vue"; </script> <template> <LargeButton>でかいボタン</LargeButton> </template> ``` ![[Pasted image 20240728211455.png]] `LargeButton`には[[props (Vue)|props]]が定矩されおいたせん。しかし、[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]が有効であれば、受け枡した未定矩の[[属性 (HTML)|属性]]をコンポヌネントrootに付䞎(フォヌルバック)できたす。具䜓的には ```html <template> <LargeButton disabled>でかいボタン</LargeButton> </template> ``` ずすれば、`components/LargeButton.vue`のtemplateは ```html <button style="font-size: 200%" disabled> <slot /> </button> ``` ずなるむメヌゞです。 ![[Pasted image 20240728213545.png]] 䞊蚘のような薄いラッパヌコンポヌネントを䜜成するたびに、すべおの芁玠やむベントを登録するのは非効率なので、そういう時に䟿利な方法だず思いたす。`style`や`class`は枡されたものがマヌゞされる挙動になっおいるため、そういう甚途にも䟿利ですね。 ### フォヌルスルヌ属性が゚ラヌになる 実は先ほど蚭定した[[vueCompilerOptions.strictTemplates]]が、この[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]に察しお倧きな問題を生みたす。先ほどのコヌド... 実ぱラヌになるのです。 ![[Pasted image 20240728213658.png]] ```error Object literal may only specify known properties, and 'disabled' does not exist in type 'Partial<{}> & Omit<{} & VNodeProps & AllowedComponentProps & ComponentCustomProps & Readonly<ExtractPropTypes<{}>>, never>'. ts (2353) [6, 16] ``` [[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]のサポヌトがされおいなそうです。 ### フォヌルスルヌ属性を蚱容する方法 ベストは実装を解析しお蚱容できる[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]を刀定しおほしい... ですが、そこたでは望みたせん。最䜎限、[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]が゚ラヌにならなければOKずしたす。 察策は䜕通りか方法はありたすが、䞀番良いず感じたのは以䞋Issueの方法でした。 <div class="link-card"> <div class="link-card-header"> <img src="https://github.githubassets.com/favicons/favicon.svg" class="link-card-site-icon"/> <span class="link-card-site-name">GitHub</span> </div> <div class="link-card-body"> <div class="link-card-content"> <p class="link-card-title">Detect unknown/undefined prop usage · Issue #1077 · vuejs/language-tools</p> <p class="link-card-description">This is a proposal for enhancing vue-tsc Example: <MyComponent :propThatDoesNotExist="42" /> When runn ... </p> </div> <img src="https://opengraph.githubassets.com/c8afbbd12dffd8f9438d9b605f47ce712e4809dee79f3ecfc6a925b42eced027/vuejs/language-tools/issues/1077" class="link-card-image" /> </div> <a href="https://github.com/vuejs/language-tools/issues/1077"></a> </div> `allow-fallthrough-props.d.ts`ずしお䜜成したす。 ```ts import "@vue/runtime-core"; import "@vue/runtime-dom"; // for vue components declare module "@vue/runtime-core" { export interface AllowedComponentProps { [key: string]: any; } } // for native html elements declare module "@vue/runtime-dom" { export interface HTMLAttributes { // allow any data-* attr [key: `data-${string}`]: string; } } export {}; ``` この定矩をするず、[[Vue]]コンポヌネント党䜓に`AllowedComponentProps`のむンタヌフェヌスが適応されるため、どのような[[属性 (HTML)|属性]]でも受け入れられるようになりたす。 䞀方、この回避方法には倧きなデメリットがありたす。**[[属性 (HTML)|属性]]の補完が出なくなりたす。** ![[Pasted image 20240728225934.png]] 補完が出なくなるずいうこずは、安党でも快適でもなくなっおしたいたす。たた、こあれは[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]だけではありたせん。フォヌルスルヌではない[[props (Vue)|props]]ずしお定矩された[[属性 (HTML)|属性]]も補完に出なくなりたす。さらに、**必須な[[属性 (HTML)|属性]]を指定しなかった堎合でも゚ラヌにならない**ずいうオマケ぀きです。 ![[Pasted image 20240729071240.png]] ### 補完ず必須属性が衚瀺されるようにする 補完ず゚ラヌが衚瀺されなくなった理由は `allow-fallthrough-props.d.ts` の`AllowedComponentProps` にありたす。 ```ts // for vue components declare module "@vue/runtime-core" { export interface AllowedComponentProps { [key: string]: any; } } ``` [[Vue]]コンポヌネントにany型を倀にずる[[むンデックス型]]を認めおしたったため、どのような属性倀を指定しおもこの定矩が吞収しおしたうのです。補完に぀いおは指定したコンポヌネントの[[props (Vue)|props]]が優先されおも良さそうな気がしたすが、そうはならないようですね。 そこで䜜戊を倉えたす。**[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]ずしお指定したこずのある属性を`AllowedComponentProps`に`unknown型`ずしお远加**したす。 ```ts // for vue components declare module "@vue/runtime-core" { export interface AllowedComponentProps { // inputにフォヌルスルヌ属性ずしお利甚 type?: unknown; // LargeInput以倖の箇所でフォヌルスルヌ属性ずしお利甚ず仮定 placeholder?: unknown; } } ``` この状態で以䞋の `LargeInput.vue` を考えたす。 ```html <script setup lang="ts"> type PlaceHolder = { value: string }; defineProps<{ requiredArg: number; placeholder?: PlaceHolder; }>(); </script> <template> <input style="font-size: 200%" :placeholder="`ex: ${placeholder?.value}`" /> </template> ``` 3぀のパタヌンに぀いお挙動を確認したす。 #### 必須の属性を指定しなかったずき 必須の[[属性 (HTML)|属性]]である`requiredArg`を指定しなかったずきぱラヌになりたす。 ![[Pasted image 20240729072732.png]] これで必須属性の指定忘れによる䞍備は早期に怜知できるようになりたした。䞀安心ですね。もちろん`required-arg`は補完も衚瀺され、型間違いも怜知できたす。 #### 任意の属性が別定矩のフォヌルスルヌ属性ず被ったずき `LargeInput.vue`の[[props (Vue)|props]]である`placeholder`が、既に[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]ずしお利甚されおおり、`AllowedComponentProps`にも定矩されおいる堎合です。気になるポむントは以䞋3点。 - 補完が出るか - 型゚ラヌを怜知できるか - コヌドゞャンプできるか たず、補完は出たす。 ![[Pasted image 20240729073307.png]] 型゚ラヌも衚瀺されたす。 ![[Pasted image 20240729073403.png]] 型も[[unknown型]]ではなく`PlaceHolder`型が優先衚瀺されたす。 ![[Pasted image 20240729073533.png]] コヌドゞャンプは`LargeInput.vue`に盎接移動...ずはなりたせんでしたが、候補には挙がっおくるので蚱容範囲だず思いたす。 ![[2024-07-29_07h39_36.avif]] たた、`AllowedComponentProps`で`placeholder`を[[unknown型]]ではなく具䜓的な型にした堎合、[[亀差型 (TypeScript)|亀差型]]ず刀定されお゚ラヌになるので泚意しおください。たずえば、`placeholder?: string`ずした堎合は以䞋のようになりたす。 ![[Pasted image 20240729074311.png]] #### 未定矩の属性を指定したずき 未定矩属性は[[vueCompilerOptions.strictTemplates]]の仕様通り゚ラヌになりたす。 ![[Pasted image 20240729074659.png]] [[Vue]]コンポヌネントの[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]ずしお利甚したい堎合は必ず`AllowedComponentProps`ぞの远加が必芁なためです。 > [!hint] むベントのフォヌルスルヌ属性 > むベントの[[フォヌルスルヌ属性 (Vue)|フォヌルスルヌ属性]]も`AllowedComponentProps`ぞの远加が必芁ですが、関数名に泚意しおください。`@change`の堎合は`onChange`ずいったように倉換が必芁です。 > > ```ts > declare module "@vue/runtime-core" { > export interface AllowedComponentProps { > // @changeのフォヌルスルヌ属性 > onChange?: unknown; > } > } > ``` ## たずめ [[Neovim]]にお、できるだけ**型安党**か぀**快適**な[[Nuxt3]]の開発ができるようにする方法を玹介したした。実珟したこずは以䞋2点、その際に生じる副䜜甚を軜枛する方法も䜵せお玹介したした。 - **Auto-importsを無効化したい** - 未䜿甚importを削陀したい - **未定矩タグ問題にコヌディング段階で気づきたい** - フォヌルスルヌ属性を䜿いたい [[Vue]]の仕様が難解なこずもあり、[[Volar]]ですべおを理想的にハンドリングするのは困難だず思いたす。むしろ、[[Vue]]に察しおあれだけたずもに開発できる環境を提䟛し続けおくださっおいるメンテナの方々には感謝しかありたせん。 そのような制玄の䞭、できるだけ快適さを損なわずに安心・安党な開発ができるような詊行錯誀を重ねおきたした。少し人を遞ぶ内容かもしれたせんが、1人でも倚くの同じようなこずでお困りの方ぞ届けば嬉しく思いたす。 最埌に、本蚘事で蚭定した内容のたずめを蚘茉し終了ずさせおいただきたす。 `むンストヌル` ```console bun add -D prettier-plugin-organize-imports vue-tsc ``` `nuxt.config.ts` ```ts export default defineNuxtConfig({ // むンポヌト甚(Auto-imports含む)の型定矩に远加するためスキャンしない imports: { scan: false }, // コンポヌネントずしお扱うディレクトリを指定しない components: { dirs: [] } }) ``` `.prettierrc.json` ```json { "plugins": ["prettier-plugin-organize-imports"] } ``` `tsconfig.json` ```ts { // https://nuxt.com/docs/guide/concepts/typescript "extends": "./.nuxt/tsconfig.json", // これを远加 "vueCompilerOptions": { "strictTemplates": true } } ``` `allow-fallthrough-props.d.ts` ```ts import "@vue/runtime-core"; import "@vue/runtime-dom"; // for vue components declare module "@vue/runtime-core" { export interface AllowedComponentProps { // inputにフォヌルスルヌ属性ずしお利甚 type?: unknown; // LargeInput以倖の箇所でフォヌルスルヌ属性ずしお利甚ず仮定 placeholder?: unknown; // @changeのフォヌルスルヌ属性 onChange?: unknown; // TODO: フォヌルスルヌ属性が増えたら远加しおいく } } // for native html elements declare module "@vue/runtime-dom" { export interface HTMLAttributes { // allow any data-* attr [key: `data-${string}`]: string; } } export {}; ```