generic throw giving Expected an object to be thrown lint error - javascript

Below throw code giving lint error Expected an object to be thrown no-throw-literal
throw { code : 403, message : myMessage };
if i try throw new Error, i am not getting eslint but it gives [Object Object] in the response.
throw new Error({ code : 403, message : myMessage });
Could someone tell me how to fix Expected an object to be thrown error ? without removing eslint config/rules

throw Object.assign(
new Error(myMessage),
{ code: 402 }
);
Throw a regular error and extend it with custom fields.
You could also write a reusable error class for that:
class CodeError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
throw new CodeError(myMessage, 404);
That way, you can distinguish the errors easily on catching:
} catch(error) {
if(error instanceof CodeError) {
console.log(error.code);
} else {
//...
}
}

Another simple workaround is store on variable and throw.
const errorMessage = { code : 403, message : myMessage };
throw errorMessage;

Related

How i can do a try catch handling error in TypeScript? [duplicate]

The Situation
I am using TypeScript, and have a try / catch block. The caught error is typed (Error). I would like to use the error's message attribute.
I am using eslint with the #typescript-eslint/no-unsafe-assignment rule enabled.
The Code
try {
throw new Error('foo');
} catch (err: Error) {
const { message }: { message: string } = err;
return {
message: `Things exploded (${message})`,
};
}
The Problem
When I run my linter, I receive the following:
4:9 error Unsafe assignment of an any value #typescript-eslint/no-unsafe-assignment
This is confusing to me, since the error is typed (Error).
The Question
How can I catch an error in TypeScript and access the Error's properties?
TypeScript 4.0 introduced the ability to declare the type of a catch clause variable... so long as you type it as unknown:
TypeScript 4.0 now lets you specify the type of catch clause variables as unknown instead. unknown is safer than any because it reminds us that we need to perform some sorts of type-checks before operating on our values.
We don't have the ability to give caught errors arbitrary types; we still need to use type guards to examine the caught value at runtime:
try {
throw new Error('foo');
} catch (err: unknown) {
if (err instanceof Error) {
return {
message: `Things exploded (${err.message})`,
};
}
}
Since Typescript 3.7 you can make an assertion type guard
export function assertIsError(error: unknown): asserts error is Error {
// if you have nodejs assert:
// assert(error instanceof Error);
// otherwise
if (!(error instanceof Error)) {
throw error
}
}
} catch (err) {
assertIsError(err);
// err is now typed as Error
return { message: `Things exploded (${err.message})` };
}
I'd suggest using the ternary operator with a type check. The accepted answer allows execution to continue in the case the error is not an Error (e.g. someone has decided to throw 42 or something equally valid yet unreasonable)
try {
throw new Error('foo');
} catch (e) {
const message = e instanceof Error ? e.message : "Unknown error."
return {
message
}
}
Visit https://devblogs.microsoft.com/typescript/announcing-typescript-4-4/
" Using unknown in Catch Variables Users running with the --strict flag may see new errors around catch variables being unknown, especially if the existing code assumes only Error values have been caught. This often results in error messages such as:
Property 'message' does not exist on type 'unknown'. Property 'name' does not exist on type 'unknown'. Property 'stack' does not exist on type 'unknown'.
To get around this, you can specifically add runtime checks to ensure that the thrown type matches your expected type. Otherwise, you can just use a type assertion,
add an explicit : any to your catch variable, or
turn off --useUnknownInCatchVariables."
you can simply add in tsconfig.json:
"compilerOptions": { "useUnknownInCatchVariables": false }
or you can use like:
catch (e: any) {console.log(e.message)}
The catch parameter type can only be any or unknown.
I think in your case it's considered as any.
Is this working in your environment?
try {
throw new Error('foo');
} catch (err: unknown) {
const { message } = err as Error; // I removed : { message: string } because it should be infered
return {
message: `Things exploded (${message})`,
};
}
TL;DR: I made a tiny library to make catching unknown safely easy:
import { asError } from 'catch-unknown';
try {
throw new Error('foo');
} catch (err) {
return {
message: `Things exploded (${asError(err).message})`,
};
}
According to Typescript's lib.es5.d.ts file, an Error is any object with string properties called name and message and optionally stack.
interface Error {
name: string;
message: string;
stack?: string;
}
In practice, errors are generally created using the Error constructor (which is required for instanceof Error to be true):
interface ErrorConstructor {
new(message?: string): Error;
(message?: string): Error;
readonly prototype: Error;
}
declare var Error: ErrorConstructor;
The catch-unknown library provides two simple functions:
export declare function isError(err: unknown): err is Error;
export declare function asError(err: unknown): Error;
isError is a typical type guard, which checks for the correct property types, as opposed to using instanceof (for maximum compatibility). asError is essentially isError(err) ? err : { name: typeof err, message: String(err) }, plus handling of a few special cases. 99.99% of the time, values you catch are already conform to Error, so all that happens is a quick type check.

How can i change the name or message of a JavaScript Error object used in Sentry?

I have a JavaScript error object that I have caught in code. It has a name, message, stack etc that I want to log at the backend. I am using sentry for that. But before logging I want to change the name or the message of the error.
What will be the best way to do it?
I tried creating a new error and adding the original error as cause, but that did not work with sentry. It just logs the error passed as the cause of the new error.
new Error('Additional error message', { cause: originalError });
I need the rest of the properties of the error to remain the same, just need to change the name or message.
I've made errors a bit readable with this:
when you capture exception, add transactionName to scope.
you can also enhance event in beforeSend method
Sentry.captureException(error, (scope) => {
...
scope.setTransactionName(`my custom title for error`);
return scope;
});
A super helpful thing you can do to accomplish this is actually create your own custom error types. This can be done by simply using a class that extends the Error constructor, like so:
class MyError extends Error {
constructor(message) {
super();
this.name = "MyError";
this.message = message;
}
}
try {
throw new MyError('this is my error')
} catch (err) {
console.log(err instanceof Error);
console.log(err.message);
console.log(err.name);
console.log(err.stack);
}
class ExtendedError extends Error {
constructor(message, { cause }) {
super();
this.name = "ExtendedError";
this.message = message;
// set the cause to maintain linkage to the original error
this.cause = cause;
}
}
try {
throw new Error('Something bad happened!');
} catch (err) {
let extendedError = new ExtendedError('Additional details', { cause: err });
console.log(extendedError instanceof Error);
console.log(extendedError.message);
console.log(extendedError.name);
console.log(extendedError.cause.stack);
console.log(extendedError.stack);
}

axios Error typescript, annotation must be 'any' or 'unknown' if?

I got error of Catch clause variable type annotation must be 'any' or 'unknown' if specified.ts(1196)
with below code
import axios, { AxiosError } from "axios";
try {
} catch(error: AxiosError) {
throw Error(error);
}
How to throw axios error in TS?
Use AxiosError to cast error
import { AxiosError } from 'axios';
catch (error) {
const err = error as AxiosError
console.log(err.response?.data)
}
I would suggest to you, removing the error type like the following:
import axios from 'axios';
try {
// do what you want with axios
// axios.get('https://example.com/some-api');
} catch (error) {
// check if the error was thrown from axios
if (axios.isAxiosError(error)) {
// do something
// or just re-throw the error
throw error;
} else {
// do something else
// or creating a new error
throw new Error('different error than axios');
}
}
I just created a stackblitz for it.
And if you want to have a deeper look just have a look at this article
You cannot write a specific annotation for the catch clause variable in typescript, this is because in javascript a catch clause will catch any exception that is thrown, not just exceptions of a specified type.
In typescript, if you want to catch just a specific type of exception, you have to catch whatever is thrown, check if it is the type of exception you want to handle, and if not, throw it again.
meaning: check if the error that is thrown is an axios error first, before doing anything.
try {
// do something
}catch (err) {
// check if error is an axios error
if (axios.isAxiosError(err)) {
// console.log(err.response?.data)
if (!err?.response) {
console.log("No Server Response");
} else if (err.response?.status === 400) {
console.log("Missing Username or Password");
} else if (err.response?.status === 401) {
console.log("Unauthorized");
} else {
console.log("Login Failed");
}
}
}

Does checking the instanceof a class inside another class have some negative side effect?

I am using ES6 Class, and I have a method like this
wrapAsync(fn) {
return (req, res) =>
fn(req, res).catch((error) => {
return this.HttpError({
statusCode: error instanceof UniqueError ? 409 : error instanceof InvalidPropertyError ? 400 : 500,
title: error.name,
message: error.message,
stack: error.stack
})
})
}
The status code is set based on the instance of which error was thrown, hence this statusCode: error instanceof UniqueError ? 409: error instanceof InvalidPropertyError ? 400 : 500. But I noticed that the ternary operator value always resulted in the falsy value, in this case, the status code always comes out as 500 even though the error is thrown is an instance of UniqueError which in this case, the status code is meant to be 409. Any idea why this might be so?
The definition of InvalidPropertyError and UniqueError looks like this
class InvalidPropertyError extends Error {
constructor(msg) {
super(msg)
this.name = 'InvalidPropertyError'
if (Error.captureStackTrace) {
Error.captureStackTrace(this, InvalidPropertyError)
}
}
}
class UniqueConstraintError extends Error {
constructor(value) {
super(`${value} must be unique.`)
this.name = 'UniqueConstraintError'
if (Error.captureStackTrace) {
Error.captureStackTrace(this, UniqueConstraintError)
}
}
}
As you can see from the above definition, I am just inheriting from the Base Error class. So somewhere in my program, I could just do an error check and throw the appropriate error. For example, assuming I am checking if a name exists or not, I just do this
...
const exist = await usersDb.find({name})
if(exist) throw UniqueError('Name already exist')
...
Now fn(req, res) is just meant to act as a middleware that will catch all errors thrown from any layer of the program, which is implemented like this.
const myFunc = ({ someDep }) => {
return http.wrapAsync(async (httpRequest) => {
const { user } = httpRequest
const { ...details } = httpRequest.body
await someDep({ user, ...details })
return http.apiResponse({
status: true,
message: 'successful',
data: null,
statusCode: 200
})
})
}
So that's how wrapAsync is implemented. It just wraps all async operations and catches any error that is being thrown.
Any help is appreciated. Thanks.

Pino error log is empty, although error object contains information

I have written a small error handling function, which is invoked after an AXIOS request, like so:
try {
...
} catch (error) {
handleAxiosError(error);
}
The function is as follows:
function handleAxiosError(error) {
if (error.response !== undefined) {
logger.error(`Received a HTTP error. Status code: ${error.response.status}, Data: ${error.response.data}`);
} else if (error.request !== undefined) {
logger.error(error.request);
} else {
logger.error(error.message);
}
throw new Error(error);
}
Although an error is thrown:
(node:94324) UnhandledPromiseRejectionWarning: Error: Error: connect ECONNREFUSED 127.0.0.1:6557
at handleAxiosError (C:\pathtoapp\utils\utils.js:66:11)
Pino only saves the following to the log. I can't find the problem. Is this an async issue?
{"level":50,"time":1567435455281,"pid":94324,"hostname":"host","name":"app","res":{},"v":1}
Thanks!
When using async logging (the default for the Pino logger), the process might have exited before all of the logging has been processed.
See https://github.com/pinojs/pino/blob/HEAD/docs/asynchronous.md
You can also change the logging to be synchronous, and you won't have this problem:
const dest = pino.destination({ sync: true })

Categories

Resources