TypeScript - Type undefined is not assignable to type ICustomType - node.js

I'm quite new to TypeScript and trying to understand what is the best way to approach such situation in my code.
I have array of objects that have a custom type in my system and I use Array.find method to get one of them. However I receive a compile error saying Type 'undefined' is not assignable to type IConfig.
Here's the code example -
const config: IConfig = CONFIGS.find(({ code }) => code === 'default');
// Type 'undefined' is not assignable to type IConfig
I tried to add undefined as possible type but then I get error on the next line which uses this object Object is possibly 'undefined', e.g. -
const config: IConfig | undefined = CONFIGS.find(({ code }) => code === 'default');
// Object is possibly 'undefined'
if (config.foo) {
return 'bar';
}
What is the best way to approach such type issues?

.find will return undefined if nothing in the array passes the callback test. If you're sure that default code exists in the array, then use the non-null assertion operator:
const config: IConfig = CONFIGS.find(({ code }) => code === 'default')!;
// ^
(If you weren't sure if it exists in the array, the warning you see is there to prompt you to explicitly test for if the item exists before trying to access a property on it, otherwise you'll sometimes get a runtime error:
const config: IConfig = CONFIGS.find(({ code }) => code === 'default');
if (!config) {
return 'No match found';
}
if (config.foo) {
return 'bar';
}
)

Related

node.js Typescript project, key-value pair

So I try to create a value pair type and get the error message: "Cannot find name 'key'."
How does it work properly?
import * as websocket from "websocket";
let wsClientsList: {[key: string]: websocket.connection};
for(key in wsClientsList){
// ^^^ TS2304: Cannot find name 'key'.
wsClientsList[key].sendUTF(message);
console.log('send Message to: ', wsClientsList[key]);
}
You need to declare a variable named key using var, let or const
for(let key in wsClientsList) {
wsClientsList[key].sendUTF(message);
console.log('send Message to: ', wsClientsList[key]);
}
You can use const in most cases in for in and for of loops, unlike in traditional for loops with increment.

Undefined property when unit testing my discord.js bot (the test itself is passed, but it is followed by an error)

I am trying to set up unit testing for my discord.js bot, but when running npm test in the terminal, while the test is being passed, still gives an error.
This is an image of the test being passed followed by the error:
https://i.imgur.com/m2EOuxc.png
I need to fix this error in testing, while still having the bot being able to function.
I have tried to completely remove the line referenced in the error (and the lines that had something to do with that specific line)
jsfiles.forEach((f, i) => {
let props = require(`./cmds/${f}`)
bot.commands.set(props.help.name, props)
})
Removing this resolved the testing issue, but resulted in the bot not functioning correctly (it did not load the commands; meaning, the bot couldn't be interacted with), which is not the goal here.
I've also checked, that each of the files in the folder cmds ends with
module.exports.help = {
name: '<name of the command I use for each command>'
}
This is the part of my bot.js file that contains the problem.
// Loads the commands for the bot:
fs.readdir('./cmds/', (err, files) => {
if (err) console.error(err)
let jsfiles = files.filter(f => f.split('.').pop() === 'js')
if (jsfiles.length <= 0) {
console.log('No commands to load!')
return
}
if (testingSettings) {
console.log(`Loading ${jsfiles.length} commands!`)
}
// This is the problem referenced above:
// ----------------------------------------------------------------------
jsfiles.forEach((f, i) => {
let props = require(`./cmds/${f}`)
bot.commands.set(props.help.name, props)
})
// ----------------------------------------------------------------------
})
This is all of my code in the bot.test.js file
const {
// Functions
checkingTesting,
// Variables
testingSettings,
} = require('./bot')
test('checking to see if testing-mode is on', () => {
expect(checkingTesting(testingSettings, 'token')).toBe(process.env['token']);
});
If it is needed. This is the function, variable and exporting method that is used to connect bot.js to bot.test.js:
Variable (in bot.js file)
const testingSettings = false
Function (in bot.js file)
function checkingTesting (testingSettings, name) {
if (testingSettings) {
return testSettings[name]
} else if (!testingSettings) {
return process.env[name]
}
}
Exporting (in bot.js file)
module.exports = {
// Exporting functions
checkingTesting: checkingTesting,
// Exporting variables
testingSettings: testingSettings,
}
props.help is undefined. The required file's exported obj is either empty, doesn't have help, or some other unforeseen event.
A good practice is to always check whether an object key exist prior using it.
if (props && props.help) {
bot.commands.set(props.help.name, props)
} else {
//throw or handle error here
}
In your command file, it seems like there is no help property of module.exports. When you try to read help.name, it throws your error because help is undefined.
Check to make sure that you're declaring module.exports.help in every command file.

NodeJS - TypeError: Cannot read property 'name' of undefined

I am getting the following error from my code: If you could help me that would be amazing! I am using discord.js!
TypeError: Cannot read property 'name' of undefined at
files.forEach.file (/root/eternity-bot/eternity-bot/index.js:21:33) at
Array.forEach () at fs.readdir
(/root/eternity-bot/eternity-bot/index.js:18:9) at
FSReqWrap.oncomplete (fs.js:135:15)
fs.readdir("./commands/", (err, files) => {
if (err) return console.error(err);
files.forEach(file => {
if (!file.endsWith(".js")) return;
let props = require(`./commands/${file}`);
console.log(`Loading Command: ${props.help.name}.`);
bot.commands.set(props.help.name, props);
props.conf.aliases.forEach(alias => {
bot.aliases.set(alias, props.help.name);
})
});
});
TypeError: A TypeError is thrown when an operand or argument passed to a function is incompatible with the type expected by that operator or function.
The possible cause is your props is not loaded correctly and doesn't include any property help, thus accessing property name of unknown property help throws TypeError. Similar to following:
let obj = {
o1: {
a: 'abc'
}
};
obj.o1 // gives {a: 'abc'}, as o1 is property obj which is an object.
obj.o1.a // gives 'abc', as a is property of o1, which is property of obj.
obj.o2 // undefined, as there's no o2 property in obj.
obj.o2.a // TypeError as there's no o2 property of obj and thus accessing property a of undefined gives error.
What is happening is that the code is working perfectly fine, but there seems to be some problem with the exports of your javascript files in the commands folder. Most probably, the help property is not defined in your files.

Typescript error TS2345 Error: TS2345:Argument of type 'Buffer' is not assignable to parameter of type 'string'

new to Typescript. I am reading some data from RabbitMQ channel and am converting it to JSON object. In this line I get the error
let communicationInformation = JSON.parse(newCommunication.content);
TS2345:Argument of type 'Buffer' is not assignable to parameter of type 'string'.
Do I need to cast the data? I am using Typescript 2.4.1
Amqplib.connect(amqpLibUrl, (err, connection) => {
if (!err) {
connection.createChannel((err, channel) => {
channel.consume('QueueName', newCommunication => {
if (newCommunication != null) {
let communicationInformation = JSON.parse(newCommunication.content);
// Code
}
})
})
}
});
I think the error is thrown on the input parameter of JSON.parse. Try to first call toString on it then pass to the function.
let communicationInformation = JSON.parse(newCommunication.content.toString());
I am not sure what is newCommunication.content. In my case it is a file and I had to specify encoding for fs.readFileSync:
const level = JSON.parse(fs.readFileSync('./path/to/file.json', 'utf-8'));
Next Error was error TS2531: Object is possibly 'null'.
You have to disable strictNullChecks in your compiler

How do I extend the Error class?

This is my code:
let errorBadRequest = new Error("Bad request");
res.statusCode = 400;
errorBadRequest.errors = err.details.reduce(function(prev, current) {
prev[current.path] = current.message;
return prev;
}, {});
throw errorBadRequest;
I wanted to extend error attribute in error instance, but tsc said joi-utils.ts(21,23): error TS2339: Property 'errors' does not exist on type 'Error'.
The structure of errors is {fieldname: fieldmsg}, it's according to my joi request schema to decide.
How do I solve the error from typescript compiler? I think I need to declare a interface and be designate the attribute.
Property 'errors' does not exist on type 'Error'.
Create a file called error-extension.d.ts and have the following:
interface Error {
errors: Error;
}
More : https://basarat.gitbooks.io/typescript/content/docs/types/lib.d.ts.html
I find when initialing the Error class, actually it hasn't errors in Error . It should make a interface and set errors to option.
This is my solution:
interface IJoiErrorException extends NodeJS.ErrnoException {
errors?: Object;
}
const errorBadRequest: IJoiErrorException = new Error("Bad request");

Resources