تایپ اسکریپت با Options API
در این صفحه فرض شده که شما از قبل بخش بررسی کلی استفاده از Vue با تایپ اسکریپت را مطالعه کرده اید.
نکته
در حالی که Vue قابلیت پشتیبانی استفاده از تایپ اسکریپت را با Options API دارد، توصیه میشود که Vue را از طریق Composition API با تایپ اسکریپت استفاده کنید، زیرا این روش سادهتر، کارآمدتر و دارای تعیین خودکار تایپ قویتری است.
تعریف تایپ Props کامپوننت
برای تعیین خودکار تایپ props در Options API نیاز است که کامپوننت با استفاده از ()defineComponent
تعریف شود. با این روش Vue قادر است بر اساس آپشن props
تایپ props را تعیین کند و همچنین آپشنهای اضافی مانند required: true
و default
را در نظر بگیرد:
ts
import { defineComponent } from 'vue'
export default defineComponent({
// تعیین خودکار تایپ فعال شده است
props: {
name: String,
id: [Number, String],
msg: { type: String, required: true },
metadata: null
},
mounted() {
this.name // تایپ: string | undefined
this.id // تایپ: number | string | undefined
this.msg // تایپ: string
this.metadata // تایپ: any
}
})
اما آپشن props
در زمان اجرای رانتایم تنها از توابع سازنده به عنوان تایپ پایه prop پشتیبانی میکنند - هیچ راهی برای مشخص کردن تایپهای پیچیده مانند آبجکتهایی با ویژگیهای تو در تو یا تشخیص امضای فراخوانی تابع وجود ندارد.
برای تعیین ویژگیهای پیچیدهی تایپهای props، میتوانیم از PropType
ابزاری برای تعیین تایپ استفاده کنیم.
ts
import { defineComponent } from 'vue'
import type { PropType } from 'vue'
interface Book {
title: string
author: string
year: number
}
export default defineComponent({
props: {
book: {
// `Object` ارائه تایپ دقیقتر به
type: Object as PropType<Book>,
required: true
},
// میتوان توابع را نیز تعیین کرد
callback: Function as PropType<(id: number) => void>
},
mounted() {
this.book.title // string
this.book.year // number
// خطای Ts : نمیتواند 'string' آرگومان از تایپ
// اختصاص داده شود 'number' به پارامتر از تایپ
this.callback?.('123')
}
})
احتیاطها
اگر نسخه TypeScript شما کمتر از 4.7
است، باید هنگام استفاده از مقادیر تابع برای گزینههای validator
و default
در props احتیاط کنید - مطمئن شوید که از arrow functions استفاده میکنید:
ts
import { defineComponent } from 'vue'
import type { PropType } from 'vue'
interface Book {
title: string
year?: number
}
export default defineComponent({
props: {
bookA: {
type: Object as PropType<Book>,
// استفاده میکنید arrow functions اگر نسخه تایپ اسکریپت شما کمتر از 4.7 است مطمئن شوید که از
default: () => ({
title: 'Arrow Function Expression'
}),
validator: (book: Book) => !!book.title
}
}
})
این کار جلوگیری میکند از حدس زدن تایپ this
در داخل توابع توسط تایپ اسکریپت، که متأسفانه گاهی میتواند باعث ایجاد مشکل در تعیین خودکار تایپ شود. این مشکل بیشتر به عنوان یک محدودیت طراحی شناخته میشد، و اکنون در تایپ اسکریپت 4.7 بهبود یافته است.
تعریف تایپ Emits کامپوننت
ما میتوانیم تایپ داده مورد انتظار برای یک رویداد emit شده را با استفاده از سینتکس آبجکت از آپشن emits
اعلام کنیم. همچنین، تمام رویدادهای emit شدهای که اعلام نشدهاند، هنگام فراخوانی، خطای تایپ ایجاد میکنند:
ts
import { defineComponent } from 'vue'
export default defineComponent({
emits: {
addBook(payload: { bookName: string }) {
// اجرای اعتبارسنجی در زمان اجرا
return payload.bookName.length > 0
}
},
methods: {
onSubmit() {
this.$emit('addBook', {
bookName: 123 // خطای تایپ!
})
this.$emit('non-declared-event') // خطای تایپ!
}
}
})
تعریف تایپ پراپرتیهای Computed
یک پراپرتی computed، تایپ خود را بر اساس مقدار بازگشتیاش تعیین میکند:
ts
import { defineComponent } from 'vue'
export default defineComponent({
data() {
return {
message: 'Hello!'
}
},
computed: {
greeting() {
return this.message + '!'
}
},
mounted() {
this.greeting // تایپ: string
}
})
در برخی موارد، ممکن است بخواهید به صراحت تایپ یک پراپرتی computed را مشخص کنید تا از صحت پیادهسازی آن اطمینان حاصل کنید:
ts
import { defineComponent } from 'vue'
export default defineComponent({
data() {
return {
message: 'Hello!'
}
},
computed: {
// به صراحت تایپ بازگشت را مشخص کردن
greeting(): string {
return this.message + '!'
},
// قابل نوشتن computed مشخص کردن تایپ یک پراپرتی
greetingUppercased: {
get(): string {
return this.greeting.toUpperCase()
},
set(newValue: string) {
this.message = newValue.toUpperCase()
}
}
}
})
در برخی موارد خاص که TypeScript به دلیل حلقههای استنباط دایرهای نمیتواند تعیین خودکار تایپ یک ویژگی computed را انجام دهد، استفاده از annotation های صریح نیز ممکن است لازم باشد.
تایپ Event Handlers
هنگام کار با رویدادهای بومی DOM، تعیین دقیق نوع آرگومانی که به تابع رویدادگیر ارسال میشود، ممکن است مفید باشد. برای درک بهتر، به مثال زیر توجه کنیم:
vue
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
methods: {
handleChange(event) {
// دارد `any` به صورت ضمنی نوع `event`
console.log(event.target.value)
}
}
})
</script>
<template>
<input type="text" @change="handleChange" />
</template>
بدون تعیین نوع ضمنی، آرگومان event به صورت ضمنی نوع any
را خواهد داشت. این امر همچنین در صورت استفاده از "strict": true
یا "noImplicitAny": true
در tsconfig.json
منجر به خطای TS میشود. بنابراین توصیه میشود که به صورت صریح نوع آرگومان رویدادگیرها را مشخص کنید. علاوه بر این، ممکن است نیاز به استفاده از ادعاهای نوعی (type assertions) هنگام دسترسی به پراپرتیهای event باشید:
ts
import { defineComponent } from 'vue'
export default defineComponent({
methods: {
handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value)
}
}
})
افزایش پراپرتیهای سراسری
برخی از پلاگینها پراپرتیهای سراسری را در تمام نمونههای ساخته شده از کامپوننت، از طریق app.config.globalProperties
نصب میکنند. به عنوان مثال، ما ممکن است this.$http
را برای دریافت دادهها یا this.$translate
را برای چند زبانه کردن نصب کنیم. برای اینکه این امکان به خوبی با TypeScript کار کند، Vue یک رابط ComponentCustomProperties
را ارائه میدهد که طراحی شده است تا از طریق افزایش ماژول TypeScript افزایش یابد:
ts
import axios from 'axios'
declare module 'vue' {
interface ComponentCustomProperties {
$http: typeof axios
$translate: (key: string) => string
}
}
همچنین ببینید:
مکان قرارگیری افزایش تایپ
ما میتوانیم این افزایش تایپ را در یک فایل .ts
قرار دهیم، یا در یک فایل پروژهای *.d.ts
. به هر حال، اطمینان حاصل کنید که در tsconfig.json
گنجانده شده است. برای نویسندگان کتابخانه/پلاگین، این فایل باید در ویژگی types
در package.json
مشخص شود.
برای بهرهبرداری از افزایش ماژول، شما باید اطمینان حاصل کنید که افزایش در یک ماژول TypeScript قرار گرفته است. به این معنا که فایل باید حداقل شامل یک import
یا export
در سطح بالا باشد، حتی اگر فقط export {}
باشد. اگر افزایش خارج از یک ماژول قرار گیرد، به جای افزایش دادن، تایپهای اصلی را بازنویسی خواهد کرد!
ts
// کار نمیکند، تایپهای اصلی را بازنویسی میکند
declare module 'vue' {
interface ComponentCustomProperties {
$translate: (key: string) => string
}
}
ts
// به درستی کار میکند
export {}
declare module 'vue' {
interface ComponentCustomProperties {
$translate: (key: string) => string
}
}
افزایش آپشنهای سفارشی
برخی از پلاگینها، به عنوان مثال vue-router
، پشتیبانی از آپشنهای سفارشی کامپوننت مانند beforeRouteEnter
را فراهم میکنند:
ts
import { defineComponent } from 'vue'
export default defineComponent({
beforeRouteEnter(to, from, next) {
// ...
}
})
بدون افزایش تایپ مناسب، آرگومانهای این هوک به صورت ضمنی نوع any
خواهند داشت. ما میتوانیم رابط ComponentCustomOptions
را برای پشتیبانی از این آپشنهای سفارشی افزایش دهیم:
ts
import { Route } from 'vue-router'
declare module 'vue' {
interface ComponentCustomOptions {
beforeRouteEnter?(to: Route, from: Route, next: () => void): void
}
}
حالا آپشن beforeRouteEnter
به درستی تایپ خواهد شد. توجه داشته باشید که این فقط یک مثال است - کتابخانههایی با تایپهای مناسب مانند vue-router
باید به صورت خودکار این افزایشها را در تعریف تایپهای خود انجام دهند.
مکان قرارگیری این افزایش مشمول همان محدودیتها به عنوان افزایشهای ویژگی سراسری است.
همچنین ببینید: