如何为未暴露泛型类型的函数加类型注解?react-native-navigation类型问题
我之前在项目里碰到过一模一样的问题,折腾了一阵终于找到几个靠谱的解决办法,分享给你:
一、让passProps匹配目标屏幕Props类型
因为@types/react-native-navigation里的push方法没有暴露泛型,直接用的话没法约束passProps的类型和目标屏幕的Props对应。我们可以通过扩展Navigator类型或者封装类型安全的导航函数来解决:
方案1:扩展Navigator类型
先自定义一个带泛型的Navigator类型,覆盖原有的push方法,然后在组件里把this.props.navigator断言成这个类型:
import { Navigation } from 'react-native-navigation'; // 定义带泛型的Navigator类型 type TypedNavigator = Omit<Navigation.Navigator, 'push'> & { push<TProps>(screenName: string, passProps?: TProps): void; }; // 在组件中使用 class MyScreen extends React.Component { goToTargetScreen = () => { // 断言成自定义的TypedNavigator const navigator = this.props.navigator as TypedNavigator; // 定义目标屏幕的Props类型 interface TargetScreenProps { userId: string; userName: string; } // 现在push会严格检查passProps的类型是否匹配TargetScreenProps navigator.push<TargetScreenProps>('TargetScreen', { userId: '123', userName: 'John Doe' }); }; render() { // ... } }
方案2:封装全局类型安全导航函数
如果项目里屏幕较多,推荐这种方式,统一管理所有屏幕的Props映射:
import { Navigation } from 'react-native-navigation'; // 先定义所有屏幕的Props映射表 type ScreenPropsMap = { HomeScreen: never; // 该屏幕不需要传参 TargetScreen: { userId: string; userName: string }; ProfileScreen: { profileId: number; isEditable: boolean }; }; // 封装类型安全的push函数 export function pushScreen<ScreenName extends keyof ScreenPropsMap>( navigator: Navigation.Navigator, screenName: ScreenName, passProps?: ScreenPropsMap[ScreenName] ) { navigator.push(screenName, passProps); } // 在组件中使用 class MyScreen extends React.Component { goToProfile = () => { // 只要传入正确的屏幕名称,TypeScript会自动提示对应的passProps结构 pushScreen(this.props.navigator, 'ProfileScreen', { profileId: 456, isEditable: true }); // 如果传错参数(比如少传isEditable),TypeScript会直接报错 }; }
二、给未暴露泛型的函数添加类型注解
针对这类第三方库中没有暴露泛型的函数,通常有两种实用方式:
方式1:类型断言 + 自定义泛型类型
先定义一个带泛型的函数类型,然后把原函数断言成这个类型:
// 假设第三方库的函数定义(没有泛型) declare function fetchRemoteData(url: string): Promise<any>; // 自定义泛型函数类型 type GenericFetchFn = <T>(url: string) => Promise<T>; // 断言原函数为自定义泛型类型 const typedFetch = fetchRemoteData as GenericFetchFn; // 使用时指定返回值类型 typedFetch<{ id: number; name: string }>('/api/user') .then(data => { console.log(data.id); // 类型安全,不会报错 });
方式2:包装成自定义泛型函数
创建一个自己的泛型函数,内部调用原函数,在包装层添加类型约束:
// 第三方库的无泛型函数 declare function fetchRemoteData(url: string): Promise<any>; // 自定义包装函数 export async function typedFetch<T>(url: string): Promise<T> { const result = await fetchRemoteData(url); return result as T; } // 使用示例 typedFetch<{ userId: string; email: string }>('/api/profile') .then(profile => { console.log(profile.email); // 类型提示正常 });
这种方式比断言更清晰,也方便统一维护类型逻辑。
内容的提问来源于stack exchange,提问作者Explosion Pills
相关产品推荐
相关产品推荐

