引子
之前的文中我们介绍了JS的灵活以及TS可以“管束”JS,那么Ts是否能在“管束”的同时,还保留代码的灵活呢?
从?
的使用说起
?
——可选属性——的使用可以极大的保持你的代码灵活,且避免xxx is not defined
问题。举个例子,我们之前聊到的菜单组件,我希望点击每个菜单项时,如果当前菜单有绑定一个“onClick”方法就在每个菜单项点击时执行,没有则忽略,类似这样:
较好的做法就是把这个onClick
后加?
作为MenuProps的一个可选属性:
export interface MenuProps {
onClick?: (selectIndex: string) => void
/**other props */
// ...
}
如此一来当你在组件中需要处理onClick时,如果这个属性可能是undefined,TS会提示你并提供解决办法:
这样就可以在开发中专注业务,而将提示可能未处理xxx is not defined
的工作交给TS,当然,这一切的前提是你对你的入参属性有清晰准确的定义。
使用&
实现类型的联合,搭配Partial
实现可选参数
我在上一篇文章中提到使用Ts可以从定义入参的type和interface开始
,还提到了一个问题,如何保证我们自己编写的button组件拥有onClick/onFocus等所有button的原生方法,以保证使用者可以无学习成本的使用它?全部实现一遍的方式过于麻烦,当然,button的原生属性、方法,React已经帮我们准备好了——ButtonHTMLAttributes,我们自定义的buttonProps只要全包含它即可,可以使用&
——交叉类型, 当然,我们肯定希望这样添加过来的原生属性都是带?
的可选属性,这样代码就更灵活了,很简单,使用Partial
即可:
interface BaseButtonProps {
/** 设置按钮样式 */
className?: string
/** 设置按钮禁用 */
disabled?: boolean
/** 设置按钮大小 */
size?: buttonSize
/** 设置按钮类型 */
btnType?: buttonType
}
// 帮助当前Button组件获取诸如onClick方法等Button的原生属性,方法
type NativeButtonProps = BaseButtonProps & ButtonHTMLAttributes<HTMLElement>
// 将所有属性均变为可选的,通过Partial实现
export type ButtonProps = Partial<NativeButtonProps>
这样开发者使用时,就和原生button的使用体验一模一样了:
使用extends
实现接口的继承,并通过Omit
实现排除
刚才举的例子介绍了如何通过&
实现类型的“继承”,你是否会好奇,继承不是extends吗?
当然,也可以。
比如我们要开发Input组件,按上面说的思路,我们可以继承React的InputHTMLAttributes,完全可以这样写:
type InputSize = 'lg' | 'sm'
export interface InputProps extends InputHTMLAttributes<HTMLElement> {
// 自定义属性
/**
* 设置input的size
*/
size?: InputSize;
}
不过这样代码会报错,是因为InputHTMLAttributes
中就有size这个属性了,当然你可以对你的自定义属性size重命名,亦或者,使用Omit“排除”这个属性,类似要求使用子类自身属性,而不继承父类特定属性
总结
上面分享的一些TS技巧都是始自对函数/纯函数中输入属性的类型限定,进而实现代码中的编码提示,错误检查提示等。其实对一个函数/纯函数的输出,也可以限定。那就是通过ReturnType。很多类型,技巧,你也可以通过这里了解更多。
使用Ts开发代码的体验就要不停地和类型死磕,这样的行为被称为:类型体操
。如果你对这些类型的实现方式感兴趣,可以看看这里,也希望大家在这些磨砺后,可以喊出那句——
迎面向我们走来的,是OpenTiny方阵
我们今天介绍的&
/extends
都跟“继承”有点关系,那么,继承到底有什么好?
最简单的好处,他能减少你的重复代码,比如上面说的button组件中,通过继承React.ButtonHTMLAttributes无需实现onClick、onFocus等方法。当然,更广泛的说,很多复杂的组件,也是组合了多个简单组件,那他们的属性之间就一定可以通过继承来简化。比如一个AutoComplete组件,就是一个Input组件加一个Select组件。那它的props可能就是这样:
当然,你也可以把很多组件的公共属性抽取出来,这样可能还能进一步简化代码,类似这样:
或者这样:
没错,这就是我们的TinyUI组件库,Angular版本的设计理念,如今TinyUI也将正式开源,欢迎微信搜索我们的小助手: opentiny-official
,了解更多信息~