Vue 3 TypeScript 接口Interface使用示例
接口在 Vue 3 中的常见应用场景
1. 定义组件 Props 类型
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// 用户信息接口interface User { id: number; name: string; email: string; age?: number; // 可选属性}// 在组件中使用export default defineComponent({ props: { // 使用接口定义props类型 user: { type: Object as () => User, // 类型断言 required: true }, // 简单类型 isActive: { type: Boolean, default: false } }, setup(props) { // 现在可以安全访问props.user的属性 const userName = computed(() => props.user.name); return { userName }; }}); |
2. 定义响应式数据模型
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
// 待办事项接口interface TodoItem { id: number; title: string; completed: boolean; createdAt: Date;}export default defineComponent({ setup() { // 使用接口定义响应式数据 const todos = ref<TodoItem[]>([ { id: 1, title: '学习 Vue 3', completed: false, createdAt: new Date() } ]); // 添加新待办事项的函数 const addTodo = (title: string) => { const newTodo: TodoItem = { id: Date.now(), title, completed: false, createdAt: new Date() }; todos.value.push(newTodo); }; return { todos, addTodo }; }}); |
3. 定义复杂的状态对象
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
// 应用状态接口interface AppState { isLoading: boolean; error: string | null; data: any[]; page: number;}export default defineComponent({ setup() { // 使用接口定义状态对象 const state = reactive<AppState>({ isLoading: false, error: null, data: [], page: 1 }); // 获取数据的方法 const fetchData = async () => { state.isLoading = true; state.error = null; try { const response = await fetch(`/api/data?page=${state.page}`); state.data = await response.json(); } catch (err) { state.error = '获取数据失败'; } finally { state.isLoading = false; } }; return { state, fetchData }; }}); |
4. 定义事件发射类型
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 自定义事件接口interface CustomEvents { (e: 'update:name', value: string): void; (e: 'delete', id: number): void;}export default defineComponent({ emits: ['update:name', 'delete'] as unknown as CustomEvents, setup(props, { emit }) { const updateName = (newName: string) => { // 类型安全的事件发射 emit('update:name', newName); }; const deleteItem = (id: number) => { // 类型安全的事件发射 emit('delete', id); }; return { updateName, deleteItem }; }}); |
5. 定义组合函数类型
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 计数器组合函数接口interface Counter { count: Ref<number>; increment: () => void; decrement: () => void; reset: () => void;}// 创建计数器的组合函数export function useCounter(initialValue = 0): Counter { const count = ref(initialValue); const increment = () => count.value++; const decrement = () => count.value--; const reset = () => count.value = initialValue; return { count, increment, decrement, reset };} |
6. 定义 API 响应类型
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// API 响应接口interface ApiResponse<T> { status: 'success' | 'error'; message: string; data: T; timestamp: Date;}// 用户数据接口interface UserData { id: number; name: string; email: string;}// 在组件中使用export default defineComponent({ setup() { const userData = ref<UserData | null>(null); const fetchUser = async (id: number) => { const response = await fetch(`/api/users/${id}`); const result: ApiResponse<UserData> = await response.json(); if (result.status === 'success') { userData.value = result.data; } }; return { userData, fetchUser }; }}); |
接口高级用法
1. 接口继承
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 基础实体接口interface BaseEntity { id: number; createdAt: Date; updatedAt: Date;}// 用户接口继承基础实体interface User extends BaseEntity { name: string; email: string; role: 'admin' | 'user';}// 产品接口继承基础实体@www.haoshilao.netinterface Product extends BaseEntity { name: string; price: number; description: string; category: string;} |
2. 索引签名
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 字典接口interface Dictionary<T> { [key: string]: T;}// 在组件中使用const colors: Dictionary<string> = { primary: '#3498db', secondary: '#2ecc71', danger: '#e74c3c'};const permissions: Dictionary<boolean> = { canEdit: true, canDelete: false, canCreate: true}; |
3. 函数类型接口
|
1
2
3
4
5
6
7
8
9
10
11
12
|
// 比较函数接口interface Comparator<T> { (a: T, b: T): number;}// 在组件中使用@www.xuepai.netconst sortUsers = (users: User[], comparator: Comparator<User>) => { return [...users].sort(comparator);};// 创建比较器const byName: Comparator<User> = (a, b) => a.name.localeCompare(b.name);const byDate: Comparator<User> = (a, b) => a.createdAt.getTime() - b.createdAt.getTime(); |
完整示例:使用接口的 Vue 3 组件
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
<template> <div class="user-profile"> <h2>{{ user.name }}</h2> <p>邮箱: {{ user.email }}</p> <p v-if="user.age">年龄: {{ user.age }}</p> <div class="stats"> <div class="stat-item"> <span class="stat-value">{{ stats.postCount }}</span> </div> <div class="stat-item"> <span class="stat-label">关注者:</span> <span class="stat-value">{{ stats.followerCount }}</span> </div> </div> <button @click="updateName">更新用户名</button> </div></template><script lang="ts">import { defineComponent, PropType, reactive } from 'vue';// 定义用户接口interface User { id: number; name: string; email: string; age?: number;}// 定义用户统计数据接口interface UserStats { postCount: number; followerCount: number; followingCount: number;}export default defineComponent({ props: { user: { type: Object as PropType<User>, required: true } }, setup(props, { emit }) { // 使用接口定义响应式状态 const stats = reactive<UserStats>({ postCount: 24, followerCount: 128, followingCount: 56 }); // 更新用户名的函数 const updateName = () => { const newName = prompt('请输入新的用户名:'); if (newName) { // 发射自定义事件 emit('update:name', newName); } }; return { stats, updateName }; }});</script><style scoped>.user-profile { max-width: 400px; margin: 0 auto; padding: 20px; border: 1px solid #e1e1e1; border-radius: 8px; background-color: #fff; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);}h2 { color: #2c3e50; margin-bottom: 10px;}p { color: #7f8c8d; margin: 5px 0;}.stats { display: flex; margin: 20px 0; border-top: 1px solid #eee; padding-top: 15px;}.stat-item { flex: 1; text-align: center;}.stat-label { display: block; color: #95a5a6; font-size: 0.9rem;}.stat-value { display: block; font-size: 1.5rem; font-weight: bold; color: #3498db;}button { background-color: #3498db; color: white; border: none; padding: 10px 15px; border-radius: 4px; cursor: pointer; font-size: 1rem; transition: background-color 0.3s;}button:hover { background-color: #2980b9;}</style> |
浙公网安备 33010602011771号