背景
我在使用 Typescript
的时候遇到过这样的一个问题。我有这样的一个组件
前面的两个搜索框是根据参数判断是否要隐藏的,Typescript
的类型定义就是这样的
type BasicItem = {
label: string
value: number
}
type BrandItem = BasicItem & {}
type PruductionItem = BasicItem & {}
type HeaderPropsType = {
hideSearch?: boolean
brandOptions: []
productionOptions: []
}
function Header(props: HeaderPropsType) {}
如果这样写的话就不能满足要求,我希望是当 hideSearch = true
的时候,brandOptions
和 productionOptions
才为必传属性,当他为 false
或者不传的时候,是非必传属性。
解决方法
1. 添加默认值
这个应该是最简单的方法了,如果你不传的话,我给你添加一个空数组不就完事了吗?也不会因为不传而导致在 undefined
上取方法属性而报错
type HeaderPropsType = {
hideSearch?: boolean
brandOptions?: []
productionOptions?: []
}
function Header({ hideSearch, brandOptions=[], productionOptions=[] }: HeaderPropsType) {}
2. 函数重载
如果是普通函数的话,可以是用函数重载的方式,大致这样,看起来好像挺复杂的,思想还是比较简单的,就是相当于我定义了几种不同情况的函数的参数和返回值而已。但是这种就不适合用在 React
函数组件上了
可以点击这里在线体验一下
type BasicItem = {
label: string
value: number
}
type BrandItem = BasicItem & {}
type ProductionItem = BasicItem & {}
type RequiredType = {
brandOptions: BrandItem[]
productionOptions: ProductionItem[]
}
type OptionalType = Partial<RequiredType>
type RequiredHideSearch = { hideSearch: true}
type OptionalHideSearch = { hideSearch?: false}
// 函数重载需要紧跟着实现
function test(props: OptionalHideSearch & RequiredType): void
function test(props: RequiredHideSearch & OptionalType): void
function test(props) {
return props
}
// 这样调用都是可以的
test({ hideSearch: true })
test({ brandOptions: [], productionOptions: [] })
test({ hideSearch: false, brandOptions: [], productionOptions: [] })
3. 类型运算
这是我比较喜欢的一种方式,当然用默认值是最简单的,也不用去定义那么多类型,但是我总觉得写 typescript
,写了那么久,好像就只会这种简单的类型添加,看源码的时候,也很难看懂人家的类型为啥这么写。
type BasicProps = {
hideSearch?: boolean
}
// 如果 hideSearch = true 就使用 T(就是BasicProps)
// 否则则使用 T & OptionListType
// 就是一个简单的三元表达式
export type HeaderProps<T> = T extends { hideSearch: true }
? T
: T & OptionListType
export type HeaderPropsType<T> = T extends BasicProps ? HeaderProps<T> : {} // 这里最后的 {} 也可以换成别的类型
function Header<T extends BasicProps>({hideSearch = false}: HeaderPropsType<T>) {}
// 使用组件的时候,就可以这样使用啦,也会有类型提示
<Header brandOpts={[]} productOpts={[]} />
<Header hideSearch={true} />
其实这里也体现了
Typescript
中,interface
和type
的一个区别,interface
就不能进行这些三元运算符的操作
总结
其实这个问题我也是问别人的,他们都说我搞那么麻烦干嘛,直接默认值不就搞定了吗?
但是我总觉得多总结总结方法,可以在以后开发的时候,思路多一些,不会只握着手中仅有的知识,止步不前。多探索探索嘛,不然总觉得自己在搬砖,多回头看看以前写的代码,有机会的话,可以总结或者优化一些,这样就不会觉得自己整天都在干相同的事情啦