TypeScript中用T|null|undefined作为Maybe<T>类型是否合理?
TypeScript中Maybe定义与空值判断的疑问
背景
我们代码库中对Maybe<T>的定义如下:
type Maybe<T> = T | null | undefined
团队规范要求,判断值是否不存在时必须使用if(foo==null){},而非if(!foo){}。同时ESLint强制使用三等号===/!==进行判断,仅允许在判断null时使用双等号==/!=,说明这种模式是团队认可的。
遇到的具体问题
1. Maybe与可选参数的类型不兼容
最突出的问题是Maybe<T>无法与TypeScript内置的可选参数类型混用:
type Props<T> = { foo: Maybe<T> bar?: T // 我认为这是内置的可选值类型 } const C = (props: Props<number>) => { const { bar, foo } = props return ( <> <C foo={foo} bar={bar} /> <C foo={foo} bar={foo} /> // bar={foo} 报错:类型 'number | null | undefined' 不能赋值给类型 'number | undefined' <C foo={bar} bar={bar} /> </> ) }
这里foo是Maybe<number>(即number | null | undefined),而可选参数bar的类型是number | undefined,所以将foo赋值给bar会触发类型错误。
2. 可选链?.与==null判断的逻辑困惑
团队规范下,以下写法是无效的:
// 无效:不符合团队判断空值的规范 if(!foo?.bar?.baz)
而以下写法是有效的:
// 有效:符合团队用!=null判断空值的要求 if(foo?.bar?.baz != null)
这让我对可选链和==null的组合使用产生困惑,主要是对逻辑等价性的理解差异:
- 按照团队要求的
==null判断逻辑,我原本认为应该写成:if(foo!=null && foo.bar!=null && foo.bar.baz!=null) - 我理解的可选链
?.的作用是简化链式存在判断,原本以为可以这样写:if(foo && foo.bar && foo.bar.baz != null) - 甚至我觉得用可选链时可以进一步简化:
if(foo && foo.bar && foo.bar.baz)
参考的其他Maybe实现
我还看到过一种更贴合JS原生行为的Maybe实现:
const toMaybe = (v)=>v??undefined
这种实现仅将undefined作为空值的表示,需要显式处理null。毕竟在JS中,访问数组越界、对象不存在的属性返回的是undefined,只有手动赋值或特定内置方法(比如document.getElementById)才会返回null。
核心疑问
- 将
null纳入“可选值”(即Maybe<T>包含null)有何弊端? - 用
==null同时判断undefined和null是否属于良好实践?
内容的提问来源于stack exchange,提问作者pailhead
相关产品推荐
相关产品推荐

