From b678fee01ac4b566e9eab4a8fc5dd07e3eadec6a Mon Sep 17 00:00:00 2001 From: NataliaTepluhina Date: Tue, 27 Apr 2021 17:33:17 +0200 Subject: [PATCH 1/3] feat: added template refs typing --- src/guide/typescript-support.md | 78 +++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/src/guide/typescript-support.md b/src/guide/typescript-support.md index a2ee5b760a..972046d8b7 100644 --- a/src/guide/typescript-support.md +++ b/src/guide/typescript-support.md @@ -90,7 +90,7 @@ For developing Vue applications with TypeScript, we strongly recommend using [Vi [WebStorm](https://www.jetbrains.com/webstorm/) also provides out-of-the-box support for both TypeScript and Vue. -## Defining Vue components +## Defining Vue Components To let TypeScript properly infer types inside Vue component options, you need to define components with `defineComponent` global method: @@ -221,10 +221,10 @@ const Component = defineComponent({ // in a computed with a setter, getter needs to be annotated greetingUppercased: { get(): string { - return this.greeting.toUpperCase(); + return this.greeting.toUpperCase() }, set(newValue: string) { - this.message = newValue.toUpperCase(); + this.message = newValue.toUpperCase() } } } @@ -298,7 +298,7 @@ const Component = defineComponent({ }) ``` -### Annotating emits +### Annotating Emits We can annotate a payload for the emitted event. Also, all non-declared emitted events will throw a type error when called: @@ -372,6 +372,76 @@ year.value = 2020 // ok! If the type of the generic is unknown, it's recommended to cast `ref` to `Ref`. ::: +### Typing Template Refs + +Sometimes you might need to annotate a template ref for a child component in order to call its public method. For example, we have a `MyModal` child component with a method that opens the modal: + +```ts +import { defineComponent, ref } from 'vue' + +export default defineComponent({ + setup() { + const isContentShown = ref(false) + const open = () => (isContentShown.value = true) + + return { + isContentShown, + open + } + } +}) +``` + +We want to call this method via a template ref from the parent component: + +```html + +``` + +```ts +import { defineComponent, ref } from 'vue' +import MyModal from './components/MyModal.vue' + +export default defineComponent({ + name: 'App', + components: { + MyModal + }, + setup() { + const modal = ref() + const openModal = () => { + modal.value.open() + } + + return { modal, openModal } + } +}) +``` + +While this will work, there is no type information about `MyModal` and its available methods. To fix this, you should use `InstanceType` when creating a ref: + +```ts +import MyModal from './components/MyModal.vue' + +export default defineComponent({ + setup() { + const modal = ref>() + const openModal = () => { + modal.value?.open() + } + + return { modal, openModal } + } +}) +``` + +Please note that you would also need to use [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) or any other way to check that `modal.value` is not undefined. + ### Typing `reactive` When typing a `reactive` property, we can use interfaces: From 04d05987bc29a345b68362f14d75a2cb3efd9260 Mon Sep 17 00:00:00 2001 From: NataliaTepluhina Date: Fri, 30 Apr 2021 17:26:39 +0200 Subject: [PATCH 2/3] fix: fixed to non-SFC --- src/guide/typescript-support.md | 46 +++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/guide/typescript-support.md b/src/guide/typescript-support.md index 972046d8b7..55718b2389 100644 --- a/src/guide/typescript-support.md +++ b/src/guide/typescript-support.md @@ -379,7 +379,7 @@ Sometimes you might need to annotate a template ref for a child component in ord ```ts import { defineComponent, ref } from 'vue' -export default defineComponent({ +const MyModal = defineComponent({ setup() { const isContentShown = ref(false) const open = () => (isContentShown.value = true) @@ -396,22 +396,34 @@ We want to call this method via a template ref from the parent component: ```html ``` ```ts import { defineComponent, ref } from 'vue' -import MyModal from './components/MyModal.vue' -export default defineComponent({ - name: 'App', +const MyModal = defineComponent({ + setup() { + const isContentShown = ref(false) + const open = () => (isContentShown.value = true) + + return { + isContentShown, + open + } + } +}) + +const app = defineComponent({ components: { MyModal }, + template: ` + + + `, setup() { const modal = ref() const openModal = () => { @@ -426,18 +438,14 @@ export default defineComponent({ While this will work, there is no type information about `MyModal` and its available methods. To fix this, you should use `InstanceType` when creating a ref: ```ts -import MyModal from './components/MyModal.vue' - -export default defineComponent({ - setup() { - const modal = ref>() - const openModal = () => { - modal.value?.open() - } - - return { modal, openModal } +setup() { + const modal = ref>() + const openModal = () => { + modal.value?.open() } -}) + + return { modal, openModal } +} ``` Please note that you would also need to use [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) or any other way to check that `modal.value` is not undefined. From e49be7b674fcf2979c274d16dd77e9d1fbb9afdd Mon Sep 17 00:00:00 2001 From: NataliaTepluhina Date: Sun, 2 May 2021 15:04:50 +0200 Subject: [PATCH 3/3] fix: removed code block --- src/guide/typescript-support.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/guide/typescript-support.md b/src/guide/typescript-support.md index 55718b2389..01d68c40d6 100644 --- a/src/guide/typescript-support.md +++ b/src/guide/typescript-support.md @@ -394,13 +394,6 @@ const MyModal = defineComponent({ We want to call this method via a template ref from the parent component: -```html - -``` - ```ts import { defineComponent, ref } from 'vue'