'Throw an error if undefined?

Is there a way to throw an error if property could not be found from data.

Problem is, it is mapping undefined instead of throwing error.

const insertIntoTable = function(data) {
    return new Promise((resolve, reject) => {
        const entry = {
            Id: data.id,
            Method: data.Method,
            Status: data.PaymentStatus,
            InsertedAt: (new Date().getTime())
        }
    }).catch((error) => {
       console.log(error); 
    });
}


Solution 1:[1]

You can check if the properties are undefined by comparing it to undefined. For example if you wanted to check the id property you could use

 if(data.id === undefined){
     throw new Error();
}

Solution 2:[2]

const insertIntoTable = function(data) {
return new Promise((resolve, reject) => {
    if(data.id){
      const entry = {
        Id: data.id,
        Method: data.Method,
        Status: data.PaymentStatus,
        InsertedAt: (new Date().getTime())
      }
      return resolve(entry);
    }
    return reject();

    })
    .then((data) => {
        // treat your entry data
    }) 
    .catch(() => {
       throw new Error("data is undefined")
    });
}

Solution 3:[3]

One way of doing it would be to take advantage of the short-circuit evaluation, and do something like:

const insertIntoTable = function(data) {
  return new Promise((resolve, reject) => {
      const entry = {
        Id: data.id || reject("data.id is undefined"),
        Method: data.Method  || reject("data.Method is undefined"),
        Status: data.PaymentStatus  || reject("data.PaymentStatus is undefined"),
        InsertedAt: (new Date().getTime())
      }
      resolve(entry);
  }).catch((error) => {
    console.log(error);
  });
}

insertIntoTable({}).then(data => console.log(data));

However, I find this hard to read, so I'm currently looking for a better alternative.

UPDATE

I had been working on a function using proxies that provides an optional or default behavior, the function is

function optional(obj, evalFunc, def) {

  // Our proxy handler
  const handler = {
    // Intercept all property access
    get: function(target, prop, receiver) {
      const res = Reflect.get(...arguments);

      // If our response is an object then wrap it in a proxy else just return
      return typeof res === "object" ? proxify(res) : res != null ? res : def;
    }
  };

  const proxify = target => {
    return new Proxy(target, handler);
  };

  // Call function with our proxified object
  return evalFunc(proxify(obj, handler));
}

And could be applied here as

const insertIntoTable = function(data) {
  return new Promise((resolve, reject) => {
      const entry = {
        Id: optional(data, t => t.Id, reject('Id is not present')),
        Method: optional(data, t => t.Method, reject('Method is not present')),
        Status: optional(data, t => t.PaymentStatus, reject('PaymentStatus is not present')),
        InsertedAt: (new Date().getTime())
      }
      resolve(entry);
  }).catch((error) => {
    console.log(error);
  });
}

insertIntoTable({}).then(data => console.log(data));

The advantage this has is that it supports deep properties access.

Solution 4:[4]

First you need to correctly start your Promise, since you are not resolving it, I like to do it like so:

const insertIntoTable = function(data) {
    return Promise.resolve()
    .then(() => {
        const entry = {
            Id: data.id,
            Method: data.Method,
            Status: data.PaymentStatus,
            InsertedAt: (new Date().getTime())
        }
        // Do something with entry
    })
    .catch((error) => {
       console.log(error); 
    });
}

This way you can throw inside you validation (instead of rejecting)

You could create a validation function that checks for undefined, like so:

const validate = property => {
    if (property === undefined) throw 'data missing required property'
    return property
}

And use it like so:

const entry = {
    Id: validate(data.id),
    Method: validate(data.Method),
    Status: validate(data.PaymentStatus),
    InsertedAt: (new Date().getTime())
}

But this way you would always get the same error. You could change it to show an error based on the property name:

const getAndValidate = (data, propertyName) => {
    const property = data[propertyName]
    if (property === undefined) throw 'data missing the required property' + propertyName
    return property 
}

And use it like so:

const entry = {
    Id: getAndValidate(data, 'id'),
    Method: getAndValidate(data, 'Method'),
    Status: getAndValidate(data, 'PaymentStatus'),
    InsertedAt: (new Date().getTime())
}

This way you get the right error everytime, but I don't like to access the attributes using string names

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jessica Bunyan
Solution 2
Solution 3
Solution 4 Denis