jestjs - فراخوانی `new` روی یک متغیر تبدیل شده به یک نوع در TypeScript
من در حال نوشتن چند تست واحد هستم و میخواهم تست کنم که سازنده من با آرگومانهای نامعتبر در زمان اجرا شکست میخورد. اگر سازنده با آرگومانهای نامعتبر در یک پروژه TS فراخوانی شود، در زمان کامپایل شکست میخورد، بنابراین ابتدا باید آن را به any تبدیل کنم.
my-class.tsexport 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.tstest('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();
// ...
});
میخواهم این را مرتب کنم تا فقط یک تبدیل انجام دهم، با تعیین یک متغیر محلی.
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();
// ...
});
من به طور مبهم به یاد دارم که یک جنریک نوشتم که پارامتر نوعی داشت و انتظار داشت یک کلاس باشد، و فکر کردم این همان نحوهای است که آن را نوشتم—یک شیء با تابعی به نام new، اما اکنون نمیتوانم جایی که این را در وب پیدا کردم بیابم، و حتی یادم نمیآید که اصلاً کدام پروژه بود که در آن این را نوشتم.
به هر حال، با این کد تایپاسکریپت به من اخطار میدهد:
نمیتوان از 'new' با یک عبارت که نوع آن امضا برای فراخوانی یا ساخت ندارد استفاده کرد.ts(2351)
من همچنین سعی کردم { new: ... } را به { constructor: ... } تغییر دهم اما همان نتیجه را گرفتم.
من میتوانم MC را بهعنوان any رها کنم که برای تست واحد مناسب است، اما دوست دارم بدانم در آینده چگونه این کار را انجام دهم.
پاسخ شماره ۱
test('MyClass validates its constructor arguments', () => {
type Constructor<T> = new (...args: any[]) => T;
const MC = MyClass as Constructor<MyClass>;
expect(() => new MC()).toThrowErrorMatchingSnapshot();
expect(() => new MC('abc')).toThrowErrorMatchingSnapshot();
expect(() => new MC(null)).toThrowErrorMatchingSnapshot();
// ...
});
همچنین ممکن است این کار را به صورت درون خطی انجام داد، اگرچه با متغیر توضیحی واضحتر به نظر میرسد.
const MC = MyClass as new (...args: any[]) => MyClass;
در اینجا هر دو گزینه در زمین بازی هستند.
پاسخ شماره ۲
مشخص شد که من نزدیک بودم. نویسندگان تایپاسکریپت نوعی نحو عجیب برای این نوع اعلام انتخاب کردند، اما نمیتوانم صادقانه بگویم که میتوانستم چیزی بهتر ارائه کنم.
const MC = MyClass as any as new(...args[]: any[]) => MyClass;
