Típusok tesztelése
Minta Projekt
A Vitest lehetővé teszi a típusok tesztelését az expectTypeOf vagy az assertType szintaxis használatával. Alapértelmezés szerint a *.test-d.ts fájlok típusellenőrző teszteknek minősülnek, de ezt megváltoztathatod a typecheck.include konfigurációs opcióval.
A Vitest a háttérben meghívja a tsc-t vagy a vue-tsc-t a konfigurációtól függően, és elemzi az eredményeket. A Vitest a forráskódban található típushibákat is kiírja, ha talál ilyet. Ezt letilthatod a typecheck.ignoreSourceErrors konfigurációs opcióval.
Fontos megjegyezni, hogy a Vitest nem futtatja vagy fordítja le ezeket a fájlokat, csak statikusan elemzi őket a fordító. Emiatt nem használhatsz dinamikus utasításokat, például dinamikus tesztneveket, illetve a test.each, test.runIf, test.skipIf, test.concurrent API-kat. Használhatsz más API-kat, mint például a test, describe, .only, .skip, .todo API-kat.
A parancssori kapcsolók, mint például a --allowOnly és a -t szintén támogatottak a típusellenőrzéshez.
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 is a string
assertType(mount({ name: 42 }));
});Bármilyen típushiba a tesztfájlban teszthibaként lesz kezelve, így bármilyen típus trükköt használhatsz a projekted típusainak tesztelésére.
A lehetséges egyeztetők listáját az API szekcióban találhatod meg.
Hibák olvasása
Ha az expectTypeOf API-t használod, nézd meg az expect-type dokumentációját a hibaüzenetekről.
Amikor a típusok nem egyeznek, a .toEqualTypeOf és a .toMatchTypeOf egy speciális segédtípust használ a lehető leginkább használható hibaüzenetek előállításához. Azonban van némi árnyalat a megértésükben. Mivel az állítások "folyékonyan" vannak írva, a hiba a "várt" típuson kell, hogy legyen, nem a "tényleges" típuson (expect<Actual>().toEqualTypeOf<Expected>()). Ez azt jelenti, hogy a típushibák kissé zavaróak lehetnek. Ezért ez a könyvtár létrehoz egy MismatchInfo típust, hogy megpróbálja egyértelművé tenni, mi az elvárás. Például:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();Ez az állítás sikertelen lesz, mivel az {a: 1} típusa {a: number}, és nem {a: string}. A hibaüzenet ebben az esetben így néz ki:
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}>()Fontos megjegyezni, hogy a jelentett típusmegkötés egy ember által olvasható üzenet, amely meghatározza a "várt" és a "tényleges" típust is. Ahelyett, hogy szó szerint értelmeznéd a Types of property 'a' are incompatible // Type 'string' is not assignable to type "Expected: string, Actual: number" mondatot, nézd meg a tulajdonság nevét ('a') és az üzenetet: Expected: string, Actual: number. Ez a legtöbb esetben megmondja, hogy mi a baj. Az összetett típusok hibakeresése több munkát igényelhet, és némi kísérletezésre is szükség lehet. Kérlek, nyiss egy hibajegyet, ha a hibaüzenetek valójában félrevezetőek.
A toBe... függvények (pl. toBeString, toBeNumber, toBeVoid) akkor hibásodnak meg, ha nem hívható típust eredményeznek, amikor a tesztelt Actual típus nem egyezik. Például egy olyan állítás hibája, mint az expectTypeOf(1).toBeString() valami ilyesmi lesz:
test/test.ts:999:999 - error TS2349: This expression is not callable.
Type 'ExpectString<number>' has no call signatures.
999 expectTypeOf(1).toBeString()
~~~~~~~~~~A This expression is not callable rész kevésbé informatív. A lényeges hiba a következő sorban található: Type 'ExpectString<number> has no call signatures. Ez lényegében azt jelenti, hogy számot adtál át, de azt állítottad, hogy stringnek kell lennie.
Ha a TypeScript támogatná a "throw" típusokat, ezek a hibaüzenetek jelentősen javíthatók lennének. Addig nehéz lehet értelmezni őket.
Konkrét "várt" objektumok vs. típusargumentumok
Egy ilyen állítás hibaüzenetei:
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' });kevésbé informatívak, mint egy ilyen állításnál:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();Mert a TypeScript fordítónak következtetnie kell a .toEqualTypeOf({a: ''}) stílus típusargumentumára, és ez a könyvtár csak úgy tudja megjelölni hibaként, hogy összehasonlítja egy általános Mismatch típussal. Tehát, ahol lehetséges, használj típusparamétert a konkrét típusok helyett a .toEqualTypeOf és a .toMatchTypeOf esetében. Ha sokkal kényelmesebb két konkrét típust összehasonlítani, használhatod a typeof-ot:
const one = valueFromFunctionOne({ some: { complex: inputs } });
const two = valueFromFunctionTwo({ some: { other: inputs } });
expectTypeOf(one).toEqualTypeof<typeof two>();Ha nehézséget okoz az expectTypeOf API használata és a hibák feltárása, mindig használhatod az egyszerűbb assertType API-t:
const answer = 42;
assertType<number>(answer);
// @ts-expect-error answer is not a string
assertType<string>(answer);TIP
A @ts-expect-error szintaxis alkalmazásakor érdemes megbizonyosodni arról, hogy nem írtál el valamit. Ezt úgy teheted meg, hogy a típusfájljaidat belefoglalod a test.include konfigurációs opcióba, így a Vitest ténylegesen futtatja ezeket a teszteket, és ReferenceError-ral fog megbukni.
Ez átmegy, mert hibát vár, de a "answer" szó el van írva, így ez egy hamis pozitív hiba:
// @ts-expect-error answer is not a string
assertType<string>(answr); //Típusellenőrzés futtatása
Vitest 1.0-tól a típusellenőrzés engedélyezéséhez csak add hozzá a --typecheck flag-et a Vitest parancsodhoz a package.json fájlban:
{
"scripts": {
"test": "vitest --typecheck"
}
}Most futtathatod a típusellenőrzést:
npm run testyarn testpnpm run testbun testA Vitest a tsc --noEmit vagy a vue-tsc --noEmit parancsot használja a konfigurációtól függően, így eltávolíthatod ezeket a scripteket a pipeline-ból.