Sách nấu ăn Vue + TypeScript
LƯU Ý: Sách nấu ăn này giả định bạn đã có kiến thức cơ bản về TypeScript.
Thiết lập ban đầu
Thiết lập rất dễ dàng với vue-cli 3.x mới. Chỉ cần tạo dự án mới:
$ vue create myapp
Khi được yêu cầu, chọn để chọn thủ công các tính năng và đảm bảo rằng TypeScript được chọn từ danh sách.
Vue CLI v3.0.0-rc.7
? Please pick a preset:
default (babel, eslint)
❯ Manually select features
Với mục đích của cuốn sách nấu ăn này, chúng ta sẽ chọn không sử dụng các thành phần kiểu lớp và tiếp tục sử dụng định dạng dựa trên chức năng tiêu chuẩn.
Những điều cơ bản cần biết là gì?
Điều chính bạn cần biết là các khối script của bạn sẽ thay đổi. Mà không có TypeScript, chúng trông giống như thế này:
<script>
export default Vue {
data() {
return {
name: '',
locations: [],
};
},
methods: {
test(name) {
return name + '!';
},
},
}
</script>
Với TypeScript, chúng sẽ trông như thế này:
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
data() {
return {
name: '',
locations: [] as string[],
};
},
methods: {
test(name: string): number {
this.locations.push(name);
return this.locations.length;
},
},
});
</script>
Tôi đang sử dụng Vuex mapState
hoặc mapGetters
, và TypeScript báo rằng trạng thái/getters đã ánh xạ không tồn tại trên this
.
Đây là một known bug trong Vuex (thêm thông tin trong this PR). Lỗi chỉ xuất hiện khi sử dụng toàn bộ đối tượng và bao gồm một hoặc nhiều thuộc tính tính toán:
computed: {
...mapState(/*...*/),
someOtherProp() {}
}
Để tránh điều này, hoặc tránh việc toàn bộ:
computed: mapState(/*...*/)
hoặc định nghĩa một giao diện cho các liên kết Vuex và áp dụng nó vào thành phần của bạn:
import Vue, { VueConstructor } from 'vue';
import { mapState } from 'vuex';
import { MyState } from '@/store';
interface VuexBindings {
stateVar: string;
}
export default (Vue as VueConstructor<Vue & VuexBindings>).extend({
data() {
return {
name: '',
locations: [] as string[],
};
},
computed: {
...mapState({
stateVar: (state: MyState) => state.stateVar,
}),
nothing(): string {
return 'test';
},
},
methods: {
test(name: string): number {
console.log(this.stateVar); // no more TS error
this.locations.push(name);
return this.locations.length;
},
},
});
Làm thế nào để làm cho một hàm nằm ngoài phạm vi của thành phần Vue có ngữ cảnh this
chính xác?
import Vue from 'vue';
type ValidatorFunc = (this: InstanceType<typeof HelloWorld>) => Function;
const validator: ValidatorFunc = function() {
return () => {
if (this.name === 'bad') {
// do something
}
};
};
const HelloWorld = Vue.extend({
data() {
return {
name: '',
locations: [] as string[],
somethingHandler: {
trigger: 'blur',
handler: validator.bind(this),
},
};
},
});
export default HelloWorld;
Làm thế nào để chú thích $refs
của tôi để tránh cảnh báo/lỗi kiểu?
Một số thư viện giao diện người dùng sẽ cho phép bạn gán các tham chiếu trực tiếp vào các thành phần của họ để thực hiện cuộc gọi phương thức trực tiếp. Dưới đây là cách bạn cung cấp kiểu cho những tham chiếu đó.
Đầu tiên, một ví dụ về cách tiếp cận nhanh chóng:
export default Vue.extend({
methods: {
test() {
(this.$refs.dataTable as ElTable).clearSelection();
},
},
});
Nếu bạn tham chiếu đến cùng một tham chiếu nhiều lần, hoặc bạn có nhiều tham chiếu, thì việc tạo một giao diện sẽ dễ dàng hơn:
import Vue, { VueConstructor } from 'vue';
import { ElTable } from 'element-ui/types/table';
import GoogleMap from '@/components/shared/GoogleMap.vue';
// With this, you won't have to use "as" everywhere to cast the refs
interface Refs {
$refs: {
name: HTMLInputElement
dataTable: ElTable,
map: InstanceType<typeof GoogleMap>;
}
}
export default (Vue as VueConstructor<Vue & Refs>).extend({
...
})
Làm thế nào để chú thích hợp lý cho mixins?
Khi viết mixins, bạn sẽ muốn mở rộng Vue giống như bạn làm với một thành phần:
import Vue from 'vue';
export const myMixin = Vue.extend({
data() {
return {
counter: 0,
};
},
methods: {
increase(by: number = 1) {
this.counter += by;
},
},
});
Sau đó, trong bất kỳ thành phần Vue nào bạn muốn sử dụng mixin của bạn, hãy đảm bảo bạn mở rộng định nghĩa loại của thành phần bằng mixin của bạn:
export default (Vue as VueConstructor<
Vue & InstanceType<typeof myMixin>
>).extend({
mixins: [myMixin],
Bây giờ tất cả các phương thức/dữ liệu/thuộc tính của mixin của bạn sẽ được nhận diện và kiểu hoàn toàn.
Khi tôi sử dụng kiểu prop Array, các thuộc tính của thành phần của tôi (dữ liệu, thuộc tính tính toán, vv) bị hiển thị như lỗi kiểu!
Đây là một lỗi trong Vue 2.x và có thể dễ dàng khắc phục bằng cách sử dụng PropType
:
import Vue, { PropType } from 'vue';
import { Product } from '@/interfaces/product';
export default Vue.extend({
name: 'MyComponent',
props: {
products: {
type: Array as PropType<Product[]>,
required: true,
},
},
});
Làm thế nào để kích hoạt kiểm tra kiểu trên giá trị mặc định và hàm kiểm tra của một thuộc tính?
Giống như PropType
, còn có PropOptions
, cho phép bạn đặt thông tin về kiểu cho toàn bộ thuộc tính, không chỉ định nghĩa kiểu một cách riêng lẻ.
import Vue, { PropOptions } from 'vue';
import { Product } from '@/interfaces/product';
export default Vue.extend({
name: 'MyComponent',
props: {
products: {
type: Array,
default: () => [],
validator: function (value) {
// ... your validation code
}
} as PropOptions<Product[]>
},
});
Kết luận
Nếu có điều gì đó khiến bạn bực mình với Vue + TypeScript, hãy mở một vấn đề để thảo luận về việc thêm một công thức!
Chi tiết tải về:
Tác giả: ffxsam
Nguồn: https://github.com/ffxsam/vue-typescript-cookbook/blob/master/README.md