导读
本文从解决问题的角度出发,讲述实际开发过程中遇到的一些困惑和解决方案。
之前尽管读过一些文章,也系统的看过教程,可当TS结合React,在加上个antd还是一头雾水!
有时候TS给出的提示让人崩溃,搜也搜不到!觉得TS麻烦!不知道类型是啥!感觉声明类型和导入太麻烦!
如果你有上述经历不妨看看这篇文章。
正文
一个经典的class组件
import React from "react";
import { Modal } from "antd";
interface AddModalProps {
title: string;
}
interface AddModalState {
isVisible: boolean;
}
class AddModal extends React.PureComponent<
AddModalProps,
AddModalState
> {
constructor(props:AddModalProps) {
super(props);
this.state = {
isVisible:true,
}
}
public render() {
const { isVisible } = this.state;
const { title } = this.props;
return (
<Modal
visible={isVisible}
title={title}
onCancel={this.onCancel}></Modal>
);
}
private onCancel = () => {
this.setState({
isVisible: false,
});
}
}
export default AddModal;
声明AddModalProps我可以理解,为啥还要个AddModalState?这不麻烦吗
学习TS最好方式是自己去看定义文件
让我们把鼠标放在PureComponent
上按下F12,鼠标悬浮上面也可以得到一些提示
class PureComponent<P = {}, S = {}, SS = any> extends Component<P, S, SS> { }
class Component<P, S> {
AddModalProps
传给了 P
,AddModalState
传个了 s
,这里泛型起到关键作用,看看都约束了哪些东西
tslint won't let me format the sample code in a way that vscode likes it :(
作者也是有困惑的
用别人的东西心态还是要摆正
一个参数的构造器
constructor(props: Readonly<P>);
因为我们的构造器是覆盖了它,所以还是要声明类型
setState 函数
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
这意味着当你setState
是出现AddModalState
中没有的key
,或者类型不一致都会发生错误
this.setState({
isVisible: false,
name:"xiaodun"
});
这个提示确实不太容易读...
render(): ReactNode;
自定义组件中是对render
的 实现,所以不需要声明返回类型,会约束我们的返回
class中定义了一个未实现的方法,可以称之为抽象类
state: Readonly<S>;
不必自己加个Readonly
了,效果在于初始化后再一次的赋值
如果你在接口声明中未对属性加?号,没有初始化它会报错
AddModalState里面的引用类型使用时不需要再次声明
新增一个接口
interface Dog{
name:string;
age:number;
}
会提示你需要哪些属性
避免拼写
友情提示,有时候看不到是因为其它插件或设置影响到了,比如我打
name
的时候image.png
其实name在上面...
使用的时候
image.png
还是泛型,按住Ctrl
,把鼠标放到map
上点进去
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
U
意味着你还可以约束返回的类型
往上找
interface Array<T> {
使用第三方库时不知道返回啥类型,也不知道要啥类型
使用Modal
组件时,onClose
还是onCancel
记不清楚了,说实话,看官网真的累,同样F12进去
import OriginModal from './Modal';
import { ModalStaticFunctions } from './confirm';
export { ActionButtonProps } from './ActionButton';
export { ModalProps, ModalFuncProps } from './Modal';
declare type Modal = typeof OriginModal & ModalStaticFunctions;
declare const Modal: Modal;
export default Modal;
这变量名语义化的好,在进入ModalProps
这注释写的好!
可以先写然后自动导入
其实你用
<
开头的话,会看到这样我也是刚刚才发现...,原谅我安装了太多自动提示的插件
我今天卸载了三个
有时候你得不到提示,可能是插件正在初始话、电脑CPU过载,比如频繁触发热更新...
我想要
ref
来控制它的显示
private addModalRef = React.createRef<AddModal>();
还是泛型
function createRef<T>(): RefObject<T>;
鼠标放在createRef
上也会告诉你
在AddModal
上定义一个函数
public setVisible = (isVisible: boolean) => {
this.setState({
isVisible,
});
};
然后
实在在不行就
// @ts-ignore
as any
!. (不会是null)
比如类似这种问题,我想自己验证表单
interface APPState {
validateStatus: string;
}
this.state = {
validateStatus:""
}
image.png
说出来你可能不信,我一开始是进入到定义尝试着把它给导出来,是我想太多...
然后就看到这
declare const ValidateStatuses: ["success", "warning", "error", "validating", ""];
export declare type ValidateStatus = typeof ValidateStatuses[number];
然后神奇的脑回路就开始爱的魔力转圈圈
其实只要声明的时候改成
interface APPState {
validateStatus: "";
}
我记住你了,字符串字面量类型
再看一下Input
组件
<Input onChange={this.onChange}></Input>
private onChange = (e) => {
console.log(e.target.value);
};
这个e
是什么类型呢?
如果你通过`onChange点进去
onChange?: ChangeEventHandler<T>;
type ChangeEventHandler<T = Element> = EventHandler<ChangeEvent<T>>;
不好意思,你看的是
还是要进
Input
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
这表明你这么写是不用声明的
总结
TS虽然是大势所趋,但也要结合项目和团队成员的掌握情况,毕竟前端的业务特性摆在那里,面向对象的开发模式不是很匹配。
规则也没必要搞的过于严格,还在定义接口的时候可能不用TS已经写完了。
TS定义的再好,翻开项目代码注释少的可怜不也很头大。
网友评论