Do not throw Error in constructors

Suppose that you need to instantiate a class, which takes some dependencies as parameters in constructor. I am mostly using Angular, so those dependencies are some injectable services in my case. Something like this:

@Injectable({ providedIn: 'root' })
export class PriceManagementClient {
	private readonly allowedOptions: SomeOption[] = [];

	constructor(private readonly configurationService: ConfigurationService) {
		this.allowedOptions = this.configurationService.getValue('allowedOptions');

		if (this.allowedOptions === undefined) {
			throw new Error('Missing allowedOptions');
		}
	}
	
	doSomethingUseful() {
    // ...
	}
}

What do you think will happen if you try to instantiate this class? What will happen with that Error? How will it be handled?

In normal situations, Javascript engine is able to print stacktrace when the Error is thrown, so you can track where the problem is. But in this case, the Angular application will just crash, and no error will be printed in dev console. Which makes it extremely dificult to track it down, when you have no idea what could have gone wrong. Most likely you will only see blank screen, and the app will auto redirect to root route. Not very helpful.

Root cause is that because you have thrown Error during class instantiation, you have effectly prevented that instantion. So no instance has been created. So slightly better approach is to make sure, that the problem is logged in dev console before you throw it.

constructor() {
	// Nested somewhere ...
	const errMessage = 'We have some critical problem';
	console.error(errMessage);
	throw new Error(errMessage);
}

But that still results in whitescreen situation. So, if you really need to throw Error inside a constructor, do that it in such a way, that you do not prevent instantiation. You can use setTimeout(), so that the instance is first created, and then the Error is thrown, like this:

constructor() {
	// Nested somewhere ...
	const errMessage = 'We have some critical problem';
	console.error(errMessage);
	setTimeout(() => {
		throw new Error(errMessage);
	})
}

It still looks like a code smell though 🙂