Optional Properties 存在的问题
在日常开发中经常会遇到这样的场景,给定一个默认值为空对象,在之后渲染的时候或者从接口里拿数据,再设置一下,类似如下例子:
const Context = React.createContext({})
function C(){
const value = useMemo(()=>({
handle:() => {},
state:'xxx'
}),[])
return (
<Context.Provider value={value}>
...
</Context.Provider>
)
}
这种情况下大多数同学可能会定义 类型是这样的
type ContextType = {
handle?: () => void;
state?: string;
}
const Context = React.createContext<ContextType>({})
但是这样的写法就无法发挥 typescript
强大的类型推断能力,在使用的时候必须针对于每个值判空,比如
const { handle, state } = useContext(Context)
if(state) {
handle?.()
}
这里其实 state
已经为存在了,那么 handle
必然也是存在的,所以这样的类型定义是存在瑕疵的
使用简单的联合类型和其存在的问题
这里其实我们的类型只有 两种情况
{}
// 和
type ContextType = {
handle: () => void;
state: string;
}
如果我们这样定义 context
的类型
type ContextType = {} | {
handle: () => void;
state: string;
}
const Context = React.createContext<ContextType>({});
会出现报错,因为不能直接使用解构
需要先类型收缩一下
定义相同的可选结构, 值类型为 undefined
的类型
解决办法是定义一个具体 相同的可选结构, 值类型为 undefined
的类型,再与其联合
type TrulyContextType = {
handle: () => void;
state: string;
}
type TransformValueUndefined<T extends Record<string, any>> = Partial<{
[P in keyof T]: undefined;
}>;
type ContextType = TransformValueUndefined<TrulyContextType> | TrulyContextType
const Context = React.createContext<ContextType>({});
这样的话直接用解构, 并且当 state
存在是 handle
也存在
完整代码
type TrulyContextType = {
handle: () => void;
state: string;
}
type TransformValueUndefined<T extends Record<string, any>> = Partial<{
[P in keyof T]: undefined;
}>;
type ContextType = TransformValueUndefined<TrulyContextType> | TrulyContextType
const Context = React.createContext<ContextType>({});
function Parent() {
const value = useMemo(
() => ({
handle: () => {},
state: "xxx"
}),
[]
);
return <Context.Provider value={value}></Context.Provider>;
}
function Children() {
const { state, handle} = useContext(Context);
if(state){
handle();
}
return null;
}
此外
解构的写法的类型收缩需要 ts 4.4
补充例子(react 组件同时接收两个参数,或者都不接收)
地址:stackblitz.com/edit/react-…