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 test
yarn test
pnpm run test
bun test
A 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.