I am trying to access the value from an object. But I get the following error.
Object is possibly 'undefined' typescript
My TypeScript code:
import { SqlClient } from 'msnodesqlv8';
declare var require: any;
const sql: SqlClient = require('msnodesqlv8');
const connectionString =
'server=.,1433;Database=emps;Trusted_Connection=Yes;Driver={SQL Server Native Client 11.0}';
const query = 'SELECT * FROM [dbo].[sample] WHERE id = 117';
sql.query(connectionString, query, (err, rows) => {
console.log(rows); // this works fine, but when i try to access its value using object key, it fails
console.log(rows[0].Id); // this fails
});
This works fine in JavaScript. What is the TypeScript way of doing it.
You're getting that error because if the rows array doesn't contain any elements, then rows[0] will be undefined. Two possible solutions:
1) Check that it actually has data, e.g.
if (rows[0]) {
console.log(rows[0].Id)
}
2) Disable the strict or strictNullChecks option in your tsconfig.json (see more here). This will silence the error, but you'll get a runtime error if it actually is undefined, so you may want to check the value instead unless you're absolutely certain it will always have data.
Related
I have a Firebase Cloud Function that reads a document from Firestore, gets a map field, and gets a boolean value from one of that map's keys. However, my IDE says that the string key I use to get the value from the map (someKey in the code below) is "declared but never read", which puzzles me. Aren't I reading it when I use it to access the map? What am I doing wrong?
exports.someFunction = functions.https.onCall(async (data, _context) => {
const uid = data.uid;
const someKey = data.someKey; // function argument; guaranteed to be a string
const settingsDoc = await admin.firestore().doc("settings/" + uid).get();
const theMapInQuestion = settingsDoc.get("theMapInQuestion"); // guaranteed to be a Firestore map of type [string: boolean]
const theBooleanInQuestion = theMapInQuestion.someKey;
if (theBooleanInQuestion === true) {
// proceed
} else {
...
}
});
The message is telling you that you never used the const someKey after it was declared. Indeed, I do not see where that variable is ever used in the code you show here. You could certainly delete the line of code that declares someKey and it would work exactly the same.
The only thing you're doing wrong that I can see is assuming that the const is actually being used when the compiler says it's not. (It's rarely a good idea to doubt the compiler.)
If you intended to access the property with the value of the someKey variable, then you meant to write theMapInQuestion[someKey].
I have this existing function:
const inferProcessingError = R.ifElse(
R.propEq('conversionJobStatus', 3),
R.always('Last Process failed with error; please contact DevOps'),
R.always(null)
);
which is called like this:
const msg = inferProcessingError(jobStruct || {});
with this jobStruct:
{"id":9,"mediaGroupId":1000000,"conversionJobStatus":3,
"errorDetails": {
"Cause": {
"errorMessage": "MediaConvert Job Failed with ERROR status: ERROR Video codec [indeo4] is not a supported input video codec",
},
"Error": "Error",
}
}
and I need to create an error message string which includes the data from the Cause.errorMessage element.
This would be dead simple with a native JavaScript function, but I'm learning Ramda and want to just modify the existing code to include in the error message.
An R.prop('Cause')['errorMessage'] could work except that I can't figure out how to reference the jobStruct that was passed in to the inferProcessingError statement.
I can see that the R.ifElse and subsequent Ramda functions are able to get that reference, but when I embed an R.prop('Cause') in the error message string, it resolves to a function and not the value of the Cause element because it seems to be waiting for the data structure.
So...how do I gain access to the jobStruct reference? (arguments is not defined here).
UPDATE:
I can get this to work by referencing the original jobStruct as in R.Prop('ErrorDetails', jobStruct)['Cause']['errorMessage'] but that seems rather kludgy to me...
BUT if the call to inferProcessingError is actually inside a map statement and references an element in a larger structure, then the map index is not available to reference the data structure for the R.prop.
Perhaps you could use the pipe and path methods to achieve this "the ramda way".
Begin by using ramda's path() function to extract the nested errorMessage value from the input jobStruct object. Next, enclose that in a pipe() that transforms the extracted message into a string formatted with a custom error prefix:
const incCount = R.ifElse(
R.propEq('conversionJobStatus', 3),
/* Evaluate this pipe if the error case is satisfied */
R.pipe(
/* Path to extract message from input object */
R.path(["errorDetails", "Cause", "errorMessage"]),
/* Prefix string to extracted error message */
R.concat('Custom error prefix:')),
R.always('')
);
incCount({"id":9,"mediaGroupId":1000000,"conversionJobStatus":3,
"errorDetails": {
"Cause": {
"errorMessage": "MediaConvert Job Failed with ERROR etc etc",
},
"Error": "Error",
}
});
Here's a working example - hope that helps!
Update
Thanks to #customcommander for the suggestion to use concat for the string prefix, as well as returning an empty string value for the second branch
Prior to switching to using a hash router, I had been implementing the cy.url command frequently to assure that links were navigating to the right URL addresses throughout the application. Now that we are using hash routing cy.url no longer yields a string, instead it is yielding a function. Any ideas how to work around this or reasons this is happening?
I was getting errors through out the cypress test runner like:
AssertionError: object tested must be an array, an object, or a string, but undefined given
so I logged the typeof result console.log(typeof(cy.url)) and got function printed to the console.
cy.get(dataCyButtonAttribute)
.should('be.visible')
.click()
console.log(typeof(cy.url))
cy.url().then(url => {
const categoryId = url.split(`${linkType}/`)[1]
const category = url.split('admin/')[1]
expect(category).to.contain(linkType)
expect(categoryId).to.equal('new')
})
}
This should yield a string:
const returnedUrl = null
cy.url().then(url => {
returnedUrl = url;
});
Cypress commands are asynchronous and must be followed by .then() in order to yield useful return values.
You can refer to this Github issue for more info:
https://github.com/cypress-io/cypress/issues/2150
I have encountered the same issue. And my solution as below.
cy.url().then(($base_url) => {
let id = $base_url.substr($base_url.lastIndexOf('/'),$base_url.length)
cy.log("The id is " + id);
})
It works for me.
I'm currently getting more familiar with Node.js and I'm building out a restful API. I have a config file where I store things like the environment name (staging v prod), the port number to run my server on and a hashing secret (using sha256 to hash a user pwd).
Everything is defined except for the hashing secret (it's the last key:value entry in my object). Logging out other values works just fine - trying to log out the hashing secret just says undefined. I've been going crazy for the last 2 hours here.
config.js
var environments = {}
environments.staging = {
'httpPort': 3000,
'httpsPort': 3001,
'envName': 'staging',
'hashingSecret': 'thisIsASecret'
};
environments.production = {
'httpPort': 5000,
'httpsPort': 5001,
'envName': 'production',
'hashingSecret': 'thisIsAlsoASecret'
};
var passedEnvironment = typeof(process.env.NODE_ENV) === 'string' ? process.env.NODE_ENV.toLowerCase() : ''
// check that passed in NODE_ENV value exists in our config container object
var configEnvironment = environments.hasOwnProperty(passedEnvironment) ? environments[passedEnvironment] : environments.staging
module.exports = configEnvironment
and then my file where I have helper functions (such as a function to hash a user pwd) looks like this:
// Dependencies
var crypto = require('crypto')
var config = require('./config')
// Container for our helper functions
var helpers = {}
// Define helper functions
helpers.hash = function(str) {
// validate our string input
if (typeof(str) == 'string' && str.length > 0) {
var hash = crypto.createHmac('sha256', config.hashingSecret).update(str).digest('hex')
return hash
} else {
return false
}
}
I'm constantly seeing
TypeError: Key must be a buffer
referring to the config.hashingSecret OR, if I try to log out the hashing secret BEFORE using it to create a hash, I get 'undefined'.
I'm going absolutely crazy - particularly because all of the other object properties ARE defined. To me that means that the module is exporting correctly and the object is initialized.
Using typeof tells me that config is an object - not sure where to go from here.
UPDATE -
I figured out the solution to my issue - I was requiring an old (cached) version of my config module. I had changed the project directory structure and neglected to update all of my require statements - I was making changes to the config file in the new location but the project was continuing to use the cached file from the old location. As a result, any changes made to the file weren't being served to the project (even though they'd appear in code as I typed them out in VSCode).
I'm trying to put dynamically function call in Node.js in order to avoid a infinite list of switch-case.
Here a instance of file I want to reach :
var Object = require('../models/Object'); // it's a classic mongoose Schema's object
Here my dynamic function :
/***** post words *****/
router.post('/words', function (req, res) {
var word = req.body ;
var Theme = req.body.theme
[Theme].add[Theme](word, function(err, words) {
if(err) {
res.json(err);
throw err;
}
return res.json(words);
})
})
We suppose a case where the object.name is "Object".
The function I want to build have to call an addPost method in an another file. In order to dynamically call this files I have prepared a computed name property mechanism. Hence I always call the file corresponding to my need. If I have required Object and the user post with a Object's category value, okay it will go on the Object file to compute the Post toward the good destination. So my computed name property look as following :
console.log(req.body.name) // > "Object"
Name = req.body.name
console.log(Name) // > "Object"
Okay now,
When I enter explicitly the name of the object to cal the function, as following :
Object.functionObject()
the function works fine.
BUT if I use a dynamically value call, like :
[Name].functionOf[Name]()
the function returns me :
TypeError: Cannot read property of undefined
Also,
I have try with ${Name} but my console returns me :
TypeError: console.log(...) is not a function
I have tried to install ES6 on Node.js's side sames result for now.
How it is possible since the console.log return me the great value ?
[Theme].add[Theme]()
This code creates an array with Theme as the first value and then calls functionOf, which doesn't exist on the array type. addTheme is actually a syntax error, but the engine never reaches it.
Although I recommend using a switch, I think what you're trying to do is something like this
// define Object1, Object2 with functionObject()
var objectCollection = {};
objectCollection[Object1.name] = Object1;
objectCollection[Object2.name] = Object2;
// Then you get req.body.name later
var objectName = req.body.name;
// and call the method
objectCollection[objectName].functionObject()
This will technically work, but there are a lots of failure possibilities and relying on reflection in this way makes me nervous because your client needs to know the inner workings (object and function names for instance). This is bad.
If the behavior of these objects is that different you should probably separate these into separate routes and let your client decide which it needs if you're making an api.
You could also create a factory to return the proper object and bury the switch statement there.
I am assuming Object contains all those methods
router.post('/words', function (req, res){
var word = req.body ;
var Theme = req.body.theme; // Post
// Object.addPost();
Object[`add${Theme}`](word, function(err, words) {
if(err){
res.json(err) ;
throw err;
}
return res.json(words);
});
// if you want Object.Post.addPost then
Object[Theme][`add${Theme}`](word, function(err, words) {
if(err){
res.json(err) ;
throw err;
}
return res.json(words);
});
});