如何过滤对象中null/undefined属性?不可变对象的简洁实现方案
简洁实现可选属性的对象构建(避免添加undefined/null属性)
刚好碰到过类似的场景,给你几个更简洁的解决方案,尤其是针对对象不可变的情况:
方案1:对象展开 + 短路判断(最常用,不可变友好)
先把异步请求的结果存到变量里,再利用对象展开和短路求值来选择性添加属性,完全不修改原对象:
const bar = await some?.http?.request?.that?.can?.be?.undefined?.or?.null; const result = { foo1: 'foo1', foo2: 'foo2', foo3: 'foo3', // 只有bar不为null/undefined时,才会展开这个{ bar }对象 ...(bar != null && { bar }) };
这里的逻辑是:当bar != null为真时,&&会返回后面的{ bar },被展开到result中;如果为假,&&返回false,对象展开会忽略布尔值,所以bar属性不会被添加。
方案2:一行式简化写法(注意副作用)
如果不想单独声明bar变量,也可以把逻辑写在一行,但要注意:如果你的异步请求是有副作用的(比如每次调用都会发起实际HTTP请求),这种写法会触发两次请求,不建议用;如果是无副作用的取值(比如从缓存里拿),可以这么写:
const result = { foo1: 'foo1', foo2: 'foo2', foo3: 'foo3', ...(await some?.http?.request?.that?.can?.be?.undefined?.or?.null != null && { bar: await some?.http?.request?.that?.can?.be?.undefined?.or?.null }) };
方案3:封装工具函数(适合重复使用)
如果项目里经常需要这种逻辑,封装一个工具函数会更优雅,还能保证类型安全:
function addPropIfNotNull<T extends object, K extends string>( baseObj: T, propName: K, propValue: unknown ): T | (T & { [P in K]: Exclude<typeof propValue, null | undefined> }) { if (propValue != null) { return { ...baseObj, [propName]: propValue } as any; } return baseObj; } // 使用示例 const bar = await some?.http?.request?.that?.can?.be?.undefined?.or?.null; const result = addPropIfNotNull( { foo1: 'foo1', foo2: 'foo2', foo3: 'foo3' }, 'bar', bar );
这个函数会在属性值有效时返回一个新的带属性的对象,否则返回原对象,完美适配不可变场景。
补充:为什么原方法不适合不可变场景?
原方法是先创建对象再给result.bar赋值,这属于直接修改原对象的属性,违背了不可变对象的原则——不可变对象要求不能修改原对象,必须通过创建新对象来更新内容,所以上面的方案都是基于创建新对象的思路实现的。
内容的提问来源于stack exchange,提问作者TSR
相关产品推荐
相关产品推荐

