乐闻世界logo
搜索文章和话题

Qwik 中如何使用 TypeScript?

2月21日 15:36

Qwik 提供了完整的 TypeScript 支持,使得开发者能够在类型安全的环境下构建应用程序。以下是 Qwik 中 TypeScript 的使用方法和最佳实践:

1. 类型定义

组件 Props 类型

tsx
import { component$, PropsOf } from '@builder.io/qwik'; interface ButtonProps { label: string; onClick$: () => void; disabled?: boolean; variant?: 'primary' | 'secondary' | 'danger'; } export const Button = component$<ButtonProps>((props) => { return ( <button onClick$={props.onClick$} disabled={props.disabled} class={`btn btn-${props.variant || 'primary'}`} > {props.label} </button> ); });

使用 PropsOf

tsx
import { component$, PropsOf } from '@builder.io/qwik'; // 扩展原生 HTML 元素的类型 export const CustomInput = component$<PropsOf<'input'> & { customProp?: string; }>((props) => { return <input {...props} />; });

2. 状态管理类型

useSignal 类型

tsx
import { component$, useSignal } from '@builder.io/qwik'; export const Counter = component$(() => { const count = useSignal<number>(0); const name = useSignal<string>(''); const isActive = useSignal<boolean>(false); return ( <div> <p>Count: {count.value}</p> <input value={name.value} onInput$={(e) => name.value = e.target.value} /> <button onClick$={() => isActive.value = !isActive.value}> Toggle </button> </div> ); });

useStore 类型

tsx
import { component$, useStore } from '@builder.io/qwik'; interface User { id: number; name: string; email: string; address: { street: string; city: string; country: string; }; } export const UserProfile = component$(() => { const user = useStore<User>({ id: 1, name: 'John Doe', email: 'john@example.com', address: { street: '123 Main St', city: 'New York', country: 'USA' } }); return ( <div> <h1>{user.name}</h1> <p>{user.email}</p> <p>{user.address.city}, {user.address.country}</p> </div> ); });

3. 事件处理类型

事件类型

tsx
import { component$ } from '@builder.io/qwik'; export const Form = component$(() => { const handleSubmit$ = (event: Event, element: HTMLFormElement) => { event.preventDefault(); const formData = new FormData(element); console.log(formData); }; const handleInput$ = (event: InputEvent, element: HTMLInputElement) => { console.log(element.value); }; const handleClick$ = (event: MouseEvent, element: HTMLButtonElement) => { console.log('Clicked', element); }; return ( <form onSubmit$={handleSubmit$}> <input type="text" onInput$={handleInput$} /> <button onClick$={handleClick$}>Submit</button> </form> ); });

自定义事件类型

tsx
import { component$ } from '@builder.io/qwik'; interface CustomEvent { detail: { id: string; value: number; }; } export const CustomComponent = component$(() => { const handleCustomEvent$ = (event: CustomEvent) => { console.log(event.detail.id, event.detail.value); }; return <div onCustomEvent$={handleCustomEvent$}>Custom Component</div>; });

4. 路由类型

路由参数类型

tsx
import { component$, routeLoader$ } from '@builder.io/qwik-city'; interface ProductParams { id: string; category?: string; } export const useProductData = routeLoader$<ProductParams>(async ({ params }) => { const response = await fetch(`https://api.example.com/products/${params.id}`); return response.json(); }); export default component$(() => { const product = useProductData(); return <div>{product.value.name}</div>; });

路由加载器类型

tsx
import { routeLoader$ } from '@builder.io/qwik-city'; interface Product { id: number; name: string; price: number; description: string; } export const useProduct = routeLoader$<Product>(async ({ params }) => { const response = await fetch(`https://api.example.com/products/${params.id}`); return response.json(); });

5. Action 类型

表单 Action 类型

tsx
import { action$, zod$, z } from '@builder.io/qwik-city'; interface FormData { name: string; email: string; message: string; } interface ActionResult { success: boolean; error?: string; } export const useContactForm = action$<FormData, ActionResult>( async (data) => { // 处理表单数据 return { success: true }; }, zod$({ name: z.string().min(2), email: z.string().email(), message: z.string().min(10) }) );

6. Context 类型

Context Provider 类型

tsx
import { component$, createContext, useContext } from '@builder.io/qwik'; interface ThemeContextValue { theme: 'light' | 'dark'; toggleTheme$: () => void; } const ThemeContext = createContext<ThemeContextValue>('theme'); export const ThemeProvider = component$(() => { const theme = useSignal<'light' | 'dark'>('light'); const toggleTheme$ = () => { theme.value = theme.value === 'light' ? 'dark' : 'light'; }; return ( <ThemeContext.Provider value={{ theme: theme.value, toggleTheme$ }}> <Child /> </ThemeContext.Provider> ); }); export const Child = component$(() => { const { theme, toggleTheme$ } = useContext(ThemeContext); return ( <div> <p>Current theme: {theme}</p> <button onClick$={toggleTheme$}>Toggle Theme</button> </div> ); });

7. 泛型组件

泛型组件定义

tsx
import { component$ } from '@builder.io/qwik'; interface ListProps<T> { items: T[]; renderItem$: (item: T, index: number) => JSXNode; keyExtractor$: (item: T) => string; } export const List = component$<ListProps<any>>((props) => { return ( <ul> {props.items.map((item, index) => ( <li key={props.keyExtractor$(item)}> {props.renderItem$(item, index)} </li> ))} </ul> ); }); // 使用示例 export const UserList = component$(() => { const users = [ { id: '1', name: 'John' }, { id: '2', name: 'Jane' } ]; return ( <List items={users} renderItem$={(user) => <span>{user.name}</span>} keyExtractor$={(user) => user.id} /> ); });

8. 类型断言和类型守卫

类型断言

tsx
import { component$ } from '@builder.io/qwik'; export const Form = component$(() => { const handleSubmit$ = (event: Event, element: HTMLFormElement) => { event.preventDefault(); // 类型断言 const input = element.querySelector('input') as HTMLInputElement; console.log(input.value); }; return ( <form onSubmit$={handleSubmit$}> <input type="text" /> <button type="submit">Submit</button> </form> ); });

类型守卫

tsx
import { component$ } from '@builder.io/qwik'; function isString(value: unknown): value is string { return typeof value === 'string'; } export const Component = component$(() => { const data = useSignal<unknown>(null); const processData$ = () => { if (isString(data.value)) { console.log(data.value.toUpperCase()); } }; return <button onClick$={processData$}>Process</button>; });

9. 类型导出和导入

类型导出

tsx
// types.ts export interface User { id: number; name: string; email: string; } export type UserRole = 'admin' | 'user' | 'guest'; export interface ApiResponse<T> { data: T; status: number; message: string; }

类型导入

tsx
// component.tsx import { component$ } from '@builder.io/qwik'; import type { User, UserRole, ApiResponse } from './types'; export const UserComponent = component$(() => { const user = useSignal<User | null>(null); const role = useSignal<UserRole>('user'); return <div>{user.value?.name}</div>; });

10. 最佳实践

1. 使用 interface 定义复杂类型

tsx
interface ComplexProps { user: { id: number; profile: { name: string; avatar: string; }; settings: { theme: string; notifications: boolean; }; }; }

2. 使用 type 定义联合类型和交叉类型

tsx
type ButtonVariant = 'primary' | 'secondary' | 'danger'; type ButtonProps = BaseProps & { variant: ButtonVariant };

3. 使用泛型提高代码复用性

tsx
export const useApi = <T>(url: string) => { return useResource$<T>(() => fetch(url).then(r => r.json())); };

4. 使用类型守卫确保类型安全

tsx
function isValidUser(user: unknown): user is User { return typeof user === 'object' && user !== null && 'id' in user; }

总结:Qwik 完全支持 TypeScript,通过类型定义、泛型、类型守卫等特性,开发者可以在类型安全的环境下构建高性能的应用程序。合理使用 TypeScript 可以提高代码质量和开发效率。

标签:Qwik