前言
都快 2021 年了,TS 早就不是什么新技术,而是前端需要掌握的硬核知识,所以今天就从一些库入手开始探究 TS 的应用以及一些小技巧
看本篇文章之前需要的一些基础知识:
- JS 基础知识
- 熟悉 react-router
- TS 官方文档至少看一遍,TS 的基本的类型了熟于心
如果没有看过 TS 官方文档的话,可以先去看官方文档,也可以试玩一下 TS 编译器,链接如下:
react-router
从古老的用法开始:
以前使用 react-router 中的 history 或者获取路由参数必须先将组件用 withRouter 包装,但是如果我们不声明 App 参数类型那么我们只能从参数中取到路由参数:
// 示例一
import React from "react";
import { withRouter } from "react-router";
const App = withRouter(({ history, match, a }) => {
// ... a取不到,会报错
// 类型“RouteComponentProps<any, StaticContext, unknown> & { children?: ReactNode; }”上不存在属性“a”。ts(2339)
});
这一堆报错我们很懵先不管他,我们直接声明 App 的参数类型:
// 示例二
import React from "react";
import { withRouter } from "react-router";
interface IProps {}
const App = withRouter(({}: IProps) => {
// 类型“({}: IProps) => any”的参数不能赋给类型“ComponentClass<RouteComponentProps<any,
// StaticContext, unknown>, any> | FunctionComponent<RouteComponentProps<any, StaticContext,
// unknown>> | (FunctionComponent<...> & ComponentClass<...>) | (ComponentClass<...> &
// FunctionComponent<...>)”的参数。
// 不能将类型“({}: IProps) => any”分配给类型“FunctionComponent<RouteComponentProps<any, StaticContext, unknown>>”。
// 参数“__0”和“props” 的类型不兼容。
// 类型 "RouteComponentProps<any, StaticContext, unknown> & { children?: ReactNode; }" 中缺少属性 "a",但类型 "IProps" 中需要该属性。
});
即使什么都不写也是一堆报错,?,此时真的不知道怎么办,TS 不知道怎么办的时候就点进去看代码,发现 withRouter 是有两个泛型参数的:
// RouteComponentProps是从react-router中声明的router参数类型,而ComponentType就是我们熟知的class组件或者函数组件,返回值我们先不管
export function withRouter<
P extends RouteComponentProps<any>,
C extends React.ComponentType<P>
>(
component: C & React.ComponentType<P>
): React.ComponentClass<
Omit<P, keyof RouteComponentProps<any>> & WithRouterProps<C>
> &
WithRouterStatics<C>;
根据这个函数的声明是否能正确地写出 withRouter 的泛型参数呢?
显然是要使用 RouteComponentProps,它需要传进去我们的路由参数
export interface RouteComponentProps<
Params extends { [K in keyof Params]?: string } = {},
C extends StaticContext = StaticContext,
S = H.LocationState
> {
history: H.History<S>;
location: H.Location<S>;
match: match<Params>;
staticContext?: C;
}
所以我们声明两个类型,一个是函数本身接受的参数,一个是路由参数
interface IProps {
name:string
}
interface IRouteProps = RouteComponentProps<{
appId:string
}>
const App = withRouter<IRouteProps, FC<IRouteProps & IProps>>(({ name, match }) => {
// appId可以获得到代码提示
// ...
// const { params: { appId } } = match
}
此时感受到了一点:从来没有像写 TS 这样的享受,能够把逻辑写的更加明确,代码更加潇洒,而且还有提示
还有一类组件,它们是路由渲染的组件,本身带有RouteComponentProps
,所以不需要使用withRouter包装
const App:FC<IRouteProps & IProps>> = ({history,match,name})=>{
}
现在 react-router 有了 hooks,我们完全可以直接使用 hooks 来获取 history对象
const App:FC<IProps> = () => {
const history = useHistory();
};
下面我们着重来看 withRouter 和 RouteComponentProps 的类型声明中的小技巧
小技巧
-
in keyof
Params extends { [K in keyof Params]?: string } = {}
这两个经常成对出现,它能够把类型中的 key 提取出来,in 则类似于遍历所有 key 设置到类型中去,上面这段代码将 Params 所有的 value 设置为可选的 string 类型
-
Omit
Omit<P, keyof RouteComponentProps<any>> & WithRouterProps<C>
Omit 是 TS 内置的类型,它的作用就是剔除掉某个属性与值,第二个参数是要剔除的属性值,详细的讲解可以参考这篇文章:
原文发布于我的博客: missop.github.io/2020/12/26/…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!