I'm writing some unit tests and I want to test that my constructor fails with invalid arguments at runtime. If the constructor is called with invalid arguments in a TS project, it fails at compile time, so I first must cast it to any.
my-class.ts
export default class MyClass {
constructor(public value: 1 | 2 | 3) {
if (!this.value ||
isNaN(this.value) ||
this.value < 1 || this.value > 3 ||
parseInt(this.value) !== this.value) {
throw new Error(`Invalid value: '${this.value}'`);
}
}
}
my-class.test.ts
test('MyClass validates its constructor arguments', () => {
expect(() => new (MyClass as any)()).toThrowErrorMatchingSnapshot();
expect(() => new (MyClass as any)('abc')).toThrowErrorMatchingSnapshot();
expect(() => new (MyClass as any)(null)).toThrowErrorMatchingSnapshot();
// ...
});
I would like to clean this up so I only make one cast, by setting a local variable.
test('MyClass validates its constructor arguments', () => {
// this type declaration isn't right
const MC = MyClass as any as { new: (...args: any[]) => MyClass };
expect(() => new MC()).toThrowErrorMatchingSnapshot();
expect(() => new MC('abc')).toThrowErrorMatchingSnapshot();
expect(() => new MC(null)).toThrowErrorMatchingSnapshot();
// ...
});
I vaguely remember writing a generic that had an type parameter expecting a class, and I thought this was how I wrote it--an object with a function called new, but I now can't find where I found that on the web, and I don't even remember which project it was I wrote it in in the first place.
At any rate, with this code TypeScript yells at me:
Cannot use 'new' with an expression whose type lacks a call or construct signature.ts(2351)
I also tried changing { new: ... } to { constructor: ... } with the same result.
I can leave MC as any which is fine for unit testing, but I'd like to know how to do this in the future.