Typen testen
Beispiel-Projekt
Vitest ermöglicht es Ihnen, Typ-Tests zu schreiben, indem Sie die Syntax expectTypeOf
oder assertType
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, abhängig von Ihrer Konfiguration, und analysiert die Ergebnisse. Vitest zeigt auch Typfehler in Ihrem Quellcode an, falls vorhanden. Sie können dies mit der Konfigurationsoption typecheck.ignoreSourceErrors
deaktivieren.
Beachten Sie, dass Vitest diese Dateien weder ausführt noch kompiliert. Sie werden lediglich statisch vom Compiler analysiert. Daher können Sie keine dynamischen Anweisungen oder dynamischen Code verwenden. Das bedeutet, dass dynamische Testnamen sowie die APIs test.each
, test.runIf
, test.skipIf
und test.concurrent
nicht unterstützt werden. Sie können jedoch andere APIs wie test
, describe
, .only
, .skip
und .todo
verwenden.
Die Verwendung von CLI-Flags wie --allowOnly
und -t
wird für die Typüberprüfung ebenfalls unterstützt.
import { assertType, expectTypeOf } from 'vitest';
import { mount } from './mount.js';
test('Meine Typen funktionieren korrekt', () => {
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. Dies ermöglicht es Ihnen, beliebige Typ-Tricks zu verwenden, um die Typen Ihres Projekts zu testen.
Eine Liste der verfügbaren Matcher finden Sie im API-Abschnitt.
Fehler interpretieren
Wenn Sie die expectTypeOf
-API verwenden, lesen Sie die Dokumentation von expect-type zu den Fehlermeldungen.
Wenn Typen nicht übereinstimmen, verwenden .toEqualTypeOf
und .toMatchTypeOf
einen speziellen Hilfstyp, um möglichst verständliche Fehlermeldungen zu erzeugen. Es gibt jedoch eine kleine Besonderheit zu beachten: Da die Assertions in Textform geschrieben sind, sollte der Fehler auf dem "erwarteten" Typ liegen, nicht auf dem "tatsächlichen" Typ (expect<Actual>().toEqualTypeOf<Expected>()
). Dies kann dazu führen, dass Typfehler etwas verwirrend erscheinen. Daher erzeugt diese Bibliothek einen MismatchInfo
-Typ, um die Erwartung klarer darzustellen. Zum Beispiel:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
Diese Assertion schlägt fehl, da {a: 1}
den Typ {a: number}
und nicht {a: string}
hat. Die Fehlermeldung in diesem Fall sieht in etwa wie folgt aus:
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 Typbeschränkung eine lesbare Nachricht ist, die sowohl die "erwarteten" als auch die "tatsächlichen" Typen angibt. Anstatt den Satz Types of property 'a' are incompatible // Type 'string' is not assignable to type "Expected: string, Actual: number"
eins zu eins zu übernehmen, betrachten Sie einfach den Eigenschaftsnamen ('a'
) und die Nachricht: Expected: string, Actual: number
. Dies wird Ihnen in den meisten Fällen sagen, was falsch ist. Extrem komplexe Typen erfordern natürlich mehr Aufwand beim Debuggen und möglicherweise einige Experimente. Bitte eröffnen Sie ein Issue, wenn die Fehlermeldungen tatsächlich irreführend sind.
Die toBe...
-Methoden (wie toBeString
, toBeNumber
, toBeVoid
usw.) schlagen fehl, indem sie zu nicht aufrufbaren Typen aufgelöst werden, wenn der Actual
-Typ unter Test nicht übereinstimmt. Beispielsweise sieht der Fehler für eine Assertion wie expectTypeOf(1).toBeString()
in etwa wie folgt aus:
test/test.ts:999:999 - error TS2349: This expression is not callable.
Type 'ExpectString<number>' has no call signatures.
999 expectTypeOf(1).toBeString()
~~~~~~~~~~
Der Teil This expression is not callable
ist nicht besonders hilfreich. Der aussagekräftige Fehler ist die nächste Zeile: Type 'ExpectString<number> has no call signatures
. Dies bedeutet im Wesentlichen, dass Sie eine Zahl übergeben haben, aber behauptet haben, dass es sich um eine Zeichenkette handeln sollte.
Wenn TypeScript die Unterstützung für "throw"-Typen hinzugefügt hätte, könnten diese Fehlermeldungen erheblich verbessert werden. Bis dahin erfordern sie genaues Hinsehen.
Konkrete Objekte vs. Typargumente
Fehlermeldungen für eine Assertion wie diese:
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' });
Sind weniger hilfreich 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 nach Möglichkeit ein Typargument anstelle eines konkreten Typs für .toEqualTypeOf
und toMatchTypeOf
. Wenn es viel 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>();
Wenn Sie Schwierigkeiten haben, mit der expectTypeOf
-API zu arbeiten und Fehler zu finden, können Sie jederzeit die einfachere assertType
-API verwenden:
const answer = 42;
assertType<number>(answer);
// @ts-expect-error answer ist keine Zeichenkette
assertType<string>(answer);
TIP
Wenn Sie die @ts-expect-error
-Syntax verwenden, sollten Sie sicherstellen, dass Sie keinen Tippfehler gemacht haben. Sie können dies tun, indem Sie Ihre Typdateien in die Konfigurationsoption test.include
aufnehmen, sodass Vitest diese Tests auch tatsächlich ausführt und mit ReferenceError
fehlschlägt.
Dies wird erfolgreich sein, da es einen Fehler erwartet, aber das Wort "answer" einen Tippfehler enthält, was zu einem falsch positiven Ergebnis führt:
// @ts-expect-error answer ist keine Zeichenkette
assertType<string>(answr); //
Typüberprüfung starten
Seit Vitest 1.0 aktivieren Sie die Typüberprüfung, indem Sie das Flag --typecheck
zu Ihrem Vitest-Befehl in package.json
hinzufügen:
{
"scripts": {
"test": "vitest --typecheck"
}
}
Jetzt können Sie die Typüberprüfung starten:
npm run test
yarn test
pnpm run test
bun test
Vitest verwendet tsc --noEmit
oder vue-tsc --noEmit
, abhängig von Ihrer Konfiguration, sodass Sie diese Skripte aus Ihrer Pipeline entfernen können.