Chào mừng bạn đến với Cafedev, nơi chúng tôi chia sẻ kiến thức và kinh nghiệm về công nghệ! Trong bài viết này, chúng ta sẽ khám phá về Vue.js với TypeScript thông qua Options API. Vue.js, một trong những framework JavaScript phổ biến nhất hiện nay, kết hợp với TypeScript, ngôn ngữ kiểu tĩnh mạnh mẽ, sẽ giúp chúng ta xây dựng ứng dụng web linh hoạt và dễ bảo trì. Hãy cùng nhau tìm hiểu cách sử dụng Options API để viết mã Vue.js có hiệu quả và dễ dàng đọc hiểu!
Trang này giả định bạn đã đọc tổng quan về Sử dụng Vue với TypeScript.
Tips: gợi ý Mặc dù Vue hỗ trợ việc sử dụng TypeScript với Options API, nhưng được khuyến nghị sử dụng Vue với TypeScript thông qua Composition API vì nó cung cấp việc suy luận kiểu đơn giản, hiệu quả và mạnh mẽ hơn.
Nội dung chính
1. Gán Kiểu Cho Props của Component
Suy luận kiểu cho props trong Options API yêu cầu bọc component bằng defineComponent()
. Với điều này, Vue có thể suy luận các loại cho props dựa trên tùy chọn props
, lấy các tùy chọn bổ sung như required: true
và default
vào tài khoản:
import { defineComponent } from 'vue'
export default defineComponent({
// type inference enabled
props: {
name: String,
id: [Number, String],
msg: { type: String, required: true },
metadata: null
},
mounted() {
this.name // type: string | undefined
this.id // type: number | string | undefined
this.msg // type: string
this.metadata // type: any
}
})
Tuy nhiên, tùy chọn props
trong thời gian chạy chỉ hỗ trợ sử dụng hàm constructor làm kiểu cho prop – không có cách nào để chỉ định các loại phức tạp như các đối tượng với các thuộc tính lồng nhau hoặc đăng ký gọi hàm.
Để chú thích các loại props phức tạp, chúng ta có thể sử dụng loại tiện ích PropType
:
import { defineComponent } from 'vue'
import type { PropType } from 'vue'
interface Book {
title: string
author: string
year: number
}
export default defineComponent({
props: {
book: {
// provide more specific type to `Object`
type: Object as PropType<Book>,
required: true
},
// can also annotate functions
callback: Function as PropType<(id: number) => void>
},
mounted() {
this.book.title // string
this.book.year // number
// TS Error: argument of type 'string' is not
// assignable to parameter of type 'number'
this.callback?.('123')
}
})
Lưu Ý
Nếu phiên bản TypeScript của bạn nhỏ hơn 4.7
, bạn phải cẩn thận khi sử dụng giá trị hàm cho các tùy chọn validator
và default
của prop – hãy đảm bảo sử dụng hàm mũi tên:
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>,
// Make sure to use arrow functions if your TypeScript version is less than 4.7
default: () => ({
title: 'Arrow Function Expression'
}),
validator: (book: Book) => !!book.title
}
}
})
Điều này ngăn TypeScript phải suy luận kiểu của this
bên trong các hàm này, điều này, không may, có thể gây suy luận kiểu thất bại. Đó là một hạn chế thiết kế trước đây, và bây giờ đã được cải thiện trong TypeScript 4.7.
2. Gán Kiểu Cho Emits cho Component
Chúng ta có thể khai báo kiểu dữ liệu mong đợi cho một sự kiện phát ra sử dụng cú pháp đối tượng của tùy chọn emits
. Ngoài ra, tất cả các sự kiện phát ra không được khai báo sẽ ném một lỗi kiểu dữ liệu khi được gọi:
import { defineComponent } from 'vue'
export default defineComponent({
emits: {
addBook(payload: { bookName: string }) {
// perform runtime validation
return payload.bookName.length > 0
}
},
methods: {
onSubmit() {
this.$emit('addBook', {
bookName: 123 // Type error!
})
this.$emit('non-declared-event') // Type error!
}
}
})
3. Gán Kiểu Cho Thuộc Tính Computed
Một thuộc tính computed suy luận kiểu của nó dựa trên giá trị trả về của nó:
import { defineComponent } from 'vue'
export default defineComponent({
data() {
return {
message: 'Hello!'
}
},
computed: {
greeting() {
return this.message + '!'
}
},
mounted() {
this.greeting // type: string
}
})
Trong một số trường hợp, bạn có thể muốn chú thích rõ ràng kiểu của một thuộc tính computed để đảm bảo hiện thực của nó là chính xác:
import { defineComponent } from 'vue'
export default defineComponent({
data() {
return {
message: 'Hello!'
}
},
computed: {
// explicitly annotate return type
greeting(): string {
return this.message + '!'
},
// annotating a writable computed property
greetingUppercased: {
get(): string {
return this.greeting.toUpperCase()
},
set(newValue: string) {
this.message = newValue.toUpperCase()
}
}
}
})
Chú thích rõ ràng cũng có thể được yêu cầu trong một số trường hợp biên khi TypeScript không thể suy luận kiểu của một thuộc tính computed do vòng lặp suy luận vòng tròn.
4. Gán Kiểu Cho Xử Lý Sự Kiện
Khi làm việc với các sự kiện DOM nguyên thủy, việc gán kiểu cho đối số mà chúng ta truyền vào xử lý viên có thể hữu ích. Hãy xem xét ví dụ sau:
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
methods: {
handleChange(event) {
// `event` implicitly has `any` type
console.log(event.target.value)
}
}
})
</script>
<template>
<input type="text" @change="handleChange" />
</template>
Nếu không có chú thích kiểu, đối số event
sẽ ngầm định có kiểu any
. Điều này cũng sẽ dẫn đến lỗi TS nếu "strict": true
hoặc "noImplicitAny": true
được sử dụng trong tsconfig.json
. Do đó, được khuyến nghị chú thích rõ ràng cho đối số của các xử lý sự kiện. Ngoài ra, bạn có thể cần sử dụng khai báo kiểu khi truy cập các thuộc tính của event
:
import { defineComponent } from 'vue'
export default defineComponent({
methods: {
handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value)
}
}
})
5. Mở Rộng Các Thuộc Tính Toàn Cục
Một số plugin cài đặt các thuộc tính có sẵn toàn cục cho tất cả các trường hợp component thông qua app.config.globalProperties. Ví dụ, chúng ta có thể cài đặt this.$http
cho việc lấy dữ liệu hoặc this.$translate
cho quốc tế hóa. Để làm cho việc này hoạt động tốt với TypeScript, Vue tiếp tục mở rộng một giao diện ComponentCustomProperties
được thiết kế để được mở rộng qua Mở rộng module TypeScript:
import axios from 'axios'
declare module 'vue' {
interface ComponentCustomProperties {
$http: typeof axios
$translate: (key: string) => string
}
}
Xem thêm:
– Các bài kiểm thử đơn vị TypeScript cho các loại component mở rộng
5.1 Vị Trí Mở Rộng Kiểu
Chúng ta có thể đặt mở rộng kiểu này trong một tệp .ts
, hoặc trong một tệp *.d.ts
toàn dự án. Dù cách nào đi nữa, đảm bảo rằng nó được bao gồm trong tsconfig.json
. Đối với tác giả thư viện/plugin, tệp này nên được chỉ định trong thuộc tính types
trong package.json
.
Để tận dụng mở rộng module, bạn cần đảm bảo rằng việc mở rộng được đặt trong một module TypeScript. Nói cách khác, tệp cần chứa ít nhất một import
hoặc export
ở mức cao nhất, ngay cả khi chỉ là export {}
. Nếu việc mở rộng được đặt bên ngoài một module, nó sẽ ghi đè lên các kiểu ban đầu thay vì mở rộng chúng!
// Does not work, overwrites the original types.
declare module 'vue' {
interface ComponentCustomProperties {
$translate: (key: string) => string
}
}
// Works correctly
export {}
declare module 'vue' {
interface ComponentCustomProperties {
$translate: (key: string) => string
}
}
6. Mở Rộng Các Tùy Chọn Tùy Chỉnh
Một số plugin, ví dụ vue-router
, cung cấp hỗ trợ cho các tùy chọn component tùy chỉnh như beforeRouteEnter
:
import { defineComponent } from 'vue'
export default defineComponent({
beforeRouteEnter(to, from, next) {
// ...
}
})
Nếu không có việc mở rộng kiểu thích hợp, các đối số của hook này sẽ ngầm định có kiểu any
. Chúng ta có thể mở rộng giao diện ComponentCustomOptions
để hỗ trợ các tùy chọn tùy chỉnh này:
import { Route } from 'vue-router'
declare module 'vue' {
interface ComponentCustomOptions {
beforeRouteEnter?(to: Route, from: Route, next: () => void): void
}
}
Bây giờ tùy chọn beforeRouteEnter
sẽ được gán kiểu đúng. Lưu ý rằng đây chỉ là một ví dụ – các thư viện được gán kiểu tốt như vue-router
nên tự động thực hiện các mở rộng này trong định nghĩa kiểu của riêng mình.
Vị trí của việc mở rộng này phải tuân thủ các hạn chế tương tự như mở rộng các thuộc tính toàn cục.
Xem thêm:
Các bài kiểm thử đơn vị TypeScript cho các loại component mở rộng
Cafedev hy vọng rằng bài viết này đã giúp bạn hiểu rõ hơn về cách sử dụng Vue.js với TypeScript thông qua Options API. Với sự kết hợp mạnh mẽ này, bạn có thể xây dựng các ứng dụng web linh hoạt và dễ bảo trì. Hãy áp dụng những kiến thức bạn đã học vào dự án của mình và không ngần ngại chia sẻ trên cộng đồng Cafedev để cùng nhau phát triển hơn nữa. Đừng quên đón đọc những nội dung mới và cập nhật từ Cafedev để tiếp tục khám phá thế giới công nghệ!
Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây
Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của CafeDev để nhận được nhiều hơn nữa:
Chào thân ái và quyết thắng!