New Syntax: Omit undefined properties

Summary

I want to ask how you think about introducing omit-key syntax when the value is undefined. I think this syntax is convenient when we need to omit key of undefined value specifying arguments.There some libraries tell apart whether key exists or not even if its value is undefined. Prisma is one of them. This throws an error when specifying undefined value with key. So, I want to write codes like followed by an example.

Specification

New syntax is ? after object key.
It's also allowed to dynamic property key

var example = {
   a?:  input.a  // omitted if input.a === undefined
   [b.name]?: input.b.value // omitted if input.b.value === undefined
   c: input.c
}

If input.a = undefined, input.b.name = 'foo' and input.c = undefined, the output of example value is

{
  c: undefined
}

Usage

prisma.model.findMany({
  where: {
    required_value: query.required_value,
    city_name?: query.city_name
  }
})

and interpret if query.city_name is undefined.

prisma.model.findMany({
  where: {
    required_value: query.required_value,
  }
})

This is possible if we can transpile the first code to

function omitUndefined(value, omitKeysIfUndefined) {
  return omitKeysIfUndefined.reduce(function(r, key) {
    if(value[key] === undefined) {
      delete r[key]
    }
    return r
  }, value)
}
prisma.model.findMany({
  where: omitKeysIfUndefined({
    required_value: query.required_value,
    city_name: query.city_name
  }, ['city_name'])
})

Problem

Current if we write codes

let additionalParams = {}
if(pattern_1 !== undefined) {
  additionalParams = {
    ...additionalParams,
    pattern_1: pattern_1
  }
}
if(pattern_2 !== undefined) {
  additionalParams = {
    ...additionalParams,
    pattern_2: pattern_2
  }
}

prisma.model.findMany({
  where: {
    required_value: query.required_value,
    ...additionalParams
  }
})

and in this way, type inference is hard in typescript, and if code logic is long code becomes unreadable.

We may be able to automatically omit undefined properties in the way removing all simply by function.

const isObject = (value) => !Array.isArray(value) && typeof value === 'object' && value !== null
export function omitUndefined(
  value
) {
  if (Array.isArray(value)) {
    for (const val of value) {
      if (typeof val === 'object') {
        omitUndefined(val)
      }
    }
  }
  if (isObject(value)) {
    const iterator = Object.keys(value)
    for (const it of iterator) {
      const child = value[it]
      if (isObject(child)) {
        omitUndefined(child)
      }
      if (child === undefined) {
        delete value[it]
      }
    }
  }
  return value
}

But it's not ideal in the point of typing and it's rare but there are cases we want to remain undefined for setting defaultValue or loop logic, so configurable syntax looks ideal.

2 Likes

Related: Optional keys in objects

1 Like

Sorry for searching enough, I will discuss that thread.