Typüberprüfung
Beispielprojekt
Vitest ermöglicht es Ihnen, Typ-Tests zu schreiben, indem Sie die expectTypeOf
- oder assertType
-Syntax verwenden. Standardmäßig werden alle Tests in *.test-d.ts
-Dateien als Typ-Tests behandelt. Sie können dies jedoch mit der Konfigurationsoption typecheck.include
anpassen.
Im Hintergrund ruft Vitest tsc
oder vue-tsc
auf, je nach Ihrer Konfiguration, und parst die Ergebnisse. Vitest gibt auch Typfehler in Ihrem Quellcode aus, sofern solche gefunden werden. Sie können dieses Verhalten mit der Konfigurationsoption typecheck.ignoreSourceErrors
deaktivieren.
Bitte beachten Sie, dass Vitest diese Dateien nicht ausführt; sie werden lediglich statisch vom Compiler analysiert. Das bedeutet, dass bei der Verwendung von dynamischen Namen, test.each
oder test.for
der Testname nicht ausgewertet wird – er wird unverändert angezeigt.
WARNING
Vor Vitest 2.1 überschrieb Ihr typecheck.include
-Muster das include
-Muster, was dazu führte, dass Ihre Laufzeittests nicht ausgeführt, sondern lediglich typgeprüft wurden.
Seit Vitest 2.1, wenn sich Ihr include
und typecheck.include
überschneiden, meldet Vitest Typ-Tests und Laufzeittests als separate Einträge.
Die Verwendung von CLI-Flags, wie --allowOnly
und -t
, wird auch für die Typüberprüfung unterstützt.
import { assertType, expectTypeOf } from 'vitest';
import { mount } from './mount.js';
test('my types work properly', () => {
expectTypeOf(mount).toBeFunction();
expectTypeOf(mount).parameter(0).toMatchTypeOf<{ name: string }>();
// @ts-expect-error name ist ein String
assertType(mount({ name: 42 }));
});
Jeder Typfehler, der in einer Testdatei auftritt, wird als Testfehler behandelt. So können Sie jede gewünschte Typ-Methode oder -Technik verwenden, um die Typen Ihres Projekts zu testen.
Eine Liste der möglichen Matcher finden Sie im API-Abschnitt.
Fehler lesen
Wenn Sie die expectTypeOf
-API verwenden, lesen Sie die expect-type-Dokumentation zu ihren Fehlermeldungen.
Wenn Typen nicht übereinstimmen, verwenden .toEqualTypeOf
und .toMatchTypeOf
einen speziellen Hilfstyp, um möglichst aussagekräftige Fehlermeldungen zu erzeugen. Es gibt jedoch eine kleine Nuance im Verständnis dieser Meldungen. Da die Assertions in einer "fließenden" Syntax (fluent API) geschrieben sind, sollte der Fehler beim "erwarteten" Typ liegen, nicht beim "tatsächlichen" Typ (expect<Actual>().toEqualTypeOf<Expected>()
). Das bedeutet, dass Typfehler verwirrend sein können – daher erzeugt diese Bibliothek einen MismatchInfo
-Typ, um die Erwartung explizit darzustellen. Zum Beispiel:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
Dies ist eine Assertion, die fehlschlägt, da {a: 1}
den Typ {a: number}
und nicht {a: string}
hat. Die Fehlermeldung in diesem Fall wird etwa so lauten:
test/test.ts:999:999 - error TS2344: Type '{ a: string; }' does not satisfy the constraint '{ a: \\"Expected: string, Actual: number\\"; }'.
Types of property 'a' are incompatible.
Type 'string' is not assignable to type '\\"Expected: string, Actual: number\\"'.
999 expectTypeOf({a: 1}).toEqualTypeOf<{a: string}>()
Beachten Sie, dass die gemeldete Typ-Einschränkung eine menschenlesbare Meldung ist, die sowohl den "erwarteten" als auch den "tatsächlichen" Typ angibt. Anstatt den Satz Typen der Eigenschaft 'a' sind inkompatibel // Typ 'string' ist nicht zuweisbar zu Typ "Erwartet: string, Tatsächlich: number"
buchstäblich zu interpretieren – schauen Sie einfach auf den Eigenschaftsnamen ('a'
) und die Meldung: Erwartet: string, Tatsächlich: number
. Dies wird Ihnen in den meisten Fällen aufzeigen, was falsch ist. Extrem komplexe Typen erfordern natürlich mehr Aufwand beim Debuggen und können einige Experimente notwendig machen. Bitte eröffnen Sie ein Issue, wenn die Fehlermeldungen tatsächlich irreführend sind.
Die toBe...
-Methoden (wie toBeString
, toBeNumber
, toBeVoid
usw.) führen zu einem Fehler, indem sie zu einem nicht aufrufbaren Typ aufgelöst werden, wenn der zu testende Actual
-Typ nicht übereinstimmt. Zum Beispiel wird der Fehler für eine Assertion wie expectTypeOf(1).toBeString()
etwa so aussehen:
test/test.ts:999:999 - error TS2349: This expression is not callable.
Type 'ExpectString<number>' has no call signatures.
999 expectTypeOf(1).toBeString()
~~~~~~~~~~
Der Hinweis Dieser Ausdruck ist nicht aufrufbar
ist nicht besonders hilfreich – der aussagekräftige Fehler findet sich in der nächsten Zeile: Typ 'ExpectString<number>' hat keine Aufrufsignaturen
. Dies bedeutet im Wesentlichen, dass Sie eine Zahl übergeben haben, aber erwartet haben, dass es ein String ist.
Wenn TypeScript Unterstützung für "throw"-Typen hinzufügen könnte, könnten diese Fehlermeldungen erheblich verbessert werden. Bis dahin erfordern sie ein gewisses Maß an genauer Betrachtung.
Konkrete "erwartete" Objekte gegenüber Typargumenten
Fehlermeldungen für eine Assertion wie die folgende:
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' });
Werden weniger hilfreich sein als für eine Assertion wie diese:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
Dies liegt daran, dass der TypeScript-Compiler das Typargument für den Stil .toEqualTypeOf({a: ''})
ableiten muss, und diese Bibliothek kann es nur als Fehler markieren, indem sie es mit einem generischen Mismatch
-Typ vergleicht. Verwenden Sie daher, wo immer möglich, ein Typargument anstelle eines konkreten Typs für .toEqualTypeOf
und toMatchTypeOf
. Wenn es wesentlich bequemer ist, zwei konkrete Typen zu vergleichen, können Sie typeof
verwenden:
const one = valueFromFunctionOne({ some: { complex: inputs } });
const two = valueFromFunctionTwo({ some: { other: inputs } });
expectTypeOf(one).toEqualTypeof<typeof two>();
Falls die Arbeit mit der expectTypeOf
-API Schwierigkeiten bereitet und Fehler zu identifizieren sind, können Sie jederzeit die einfachere assertType
-API verwenden:
const answer = 42;
assertType<number>(answer);
// @ts-expect-error answer ist kein String
assertType<string>(answer);
TIP
Wenn Sie die @ts-expect-error
-Syntax anwenden, möchten Sie möglicherweise sicherstellen, dass Sie keinen Tippfehler gemacht haben. Dies können Sie tun, indem Sie Ihre Typdateien in die Konfigurationsoption test.include
aufnehmen, sodass Vitest diese Tests auch tatsächlich ausführt und mit einem ReferenceError
fehlschlägt.
Dieser Test wird bestehen, weil er einen Fehler erwartet, aber das Wort „answer“ hat einen Tippfehler, sodass es eine falsch-positive Fehlermeldung ist:
// @ts-expect-error answer ist kein String
assertType<string>(answr); //
Typüberprüfung ausführen
Um die Typüberprüfung zu aktivieren, fügen Sie einfach das Flag --typecheck
zu Ihrem Vitest-Befehl in package.json
hinzu:
{
"scripts": {
"test": "vitest --typecheck"
}
}
Jetzt können Sie die Typüberprüfung durchführen:
npm run test
yarn test
pnpm run test
bun test
Vitest verwendet tsc --noEmit
oder vue-tsc --noEmit
, abhängig von Ihrer Konfiguration, sodass diese Skripte aus der Pipeline entfernt werden können.