Típusellenőrzés
Példa projekt
A Vitest lehetővé teszi típusellenőrző tesztek írását az expectTypeOf
vagy assertType
szintaxisok használatával. Alapértelmezetten minden *.test-d.ts
kiterjesztésű fájlban lévő teszt típus tesztnek minősül, de ezt módosíthatod a typecheck.include
konfigurációs opcióval.
A Vitest a háttérben a tsc
vagy vue-tsc
parancsot hívja meg, a konfigurációtól függően, és elemzi az eredményeket. A Vitest kiírja a forráskódban található típushibákat is, ha bármilyet talál. Ezt letilthatod a typecheck.ignoreSourceErrors
konfigurációs opcióval.
Fontos megjegyezni, hogy a Vitest nem futtatja ezeket a fájlokat, csak a fordító statikusan elemzi őket. Ez azt jelenti, hogy ha dinamikus nevet, test.each
vagy test.for
metódust használsz, a teszt neve nem lesz kiértékelve – úgy jelenik meg, ahogy van.
WARNING
A Vitest 2.1 előtt a typecheck.include
felülírta az include
mintát, így a futásidejű tesztjeid valójában nem futottak; csak típusellenőrzésen estek át.
A Vitest 2.1 óta, ha az include
és a typecheck.include
átfedésben van, a Vitest külön bejegyzésként jelenti a típus teszteket és a futásidejű teszteket.
A CLI 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ármely típushiba, amely egy tesztfájlban keletkezik, teszthibaként lesz kezelve, így bármilyen típusos technikát használhatsz a projekt típusainak teszteléséhez.
A lehetséges illesztő funkciók listáját az API szakaszban találod.
Hibák értelmezése
Ha az expectTypeOf
API-t használod, tekintsd 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, hogy a lehető leghasznosabb hibaüzeneteket állítsa elő. A megértésük azonban némi árnyalást igényel. Mivel az állítások láncolhatóan vannak megírva, a hibának az "elvárt" típusnál kell jelentkeznie, nem a "tényleges" típusnál (expect<Actual>().toEqualTypeOf<Expected>()
). Ez azt jelenti, hogy a típushibák zavaróak lehetnek – ezért ez a könyvtár egy MismatchInfo
típust hoz létre, hogy megpróbálja explicit módon megfogalmazni, mi az elvárás. Például:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
Ez az állítás hibát fog eredményezni, mivel az {a: 1}
típusa {a: number}
és nem {a: string}
. A hibaüzenet ebben az esetben a következőképpen fog kinézni:
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}>()
Megfigyelhető, hogy a jelentett típuskorlátozás egy jól olvasható üzenet, amely mind az "elvárt", mind a "tényleges" típusokat megadja. Ahelyett, hogy szó szerint vennéd a mondatot: Types of property 'a' are incompatible // Type 'string' is not assignable to type "Expected: string, Actual: number"
, elég megnézni a tulajdonság nevét ('a'
) és az üzenetet: Expected: string, Actual: number
. Ez a legtöbb esetben megmutatja, mi a probléma. A rendkívül komplex típusok természetesen több hibakeresési erőfeszítést igényelnek, és némi kísérletezést is szükségessé tehetnek. Kérjük, nyiss egy hibajegyet, ha a hibaüzenetek valójában félrevezetőek.
A toBe...
metódusok (mint például a toBeString
, toBeNumber
, toBeVoid
stb.) úgy hibáznak, hogy nem hívható típussá válnak, ha 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()
~~~~~~~~~~
Az This expression is not callable
rész nem túl hasznos – a lényeges hiba a következő sor: 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 hozzáadná a "throw" típusok támogatását, ezek a hibaüzenetek jelentősen javulhatnának. Addig is némi odafigyelést igényelnek.
Konkrét "elvárt" objektumok vs. típusargumentumok
Az ilyen állítások hibaüzenetei:
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' });
Kevésbé hasznosak lesznek, mint az ilyen állításoké:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
Ez azért van, mert a TypeScript fordítónak ki kell következtetnie a típusargumentumot a .toEqualTypeOf({a: ''})
stílushoz, és ez a könyvtár csak úgy tudja hibaként jelezni, ha összehasonlítja egy általános Mismatch
típussal. Tehát, ahol lehetséges, használj típusargumentumot a konkrét típus helyett a .toEqualTypeOf
és toMatchTypeOf
esetén. Ha sokkal kényelmesebb két konkrét típust összehasonlítani, használhatod a typeof
operátort:
const one = valueFromFunctionOne({ some: { complex: inputs } });
const two = valueFromFunctionTwo({ some: { other: inputs } });
expectTypeOf(one).toEqualTypeof<typeof two>();
Ha nehéznek találod az expectTypeOf
API-val való munkát és a hibák felderítését, 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
Az @ts-expect-error
szintaxis használatakor érdemes ellenőrizni, hogy nem írtál-e 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 futtatni fogja ezeket a teszteket, és ReferenceError
hibát fog dobni.
Ez át fog menni, mert hibát vár, de az „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
A típusellenőrzés engedélyezéséhez egyszerűen add hozzá a --typecheck
flaget a Vitest parancsodhoz a package.json
fájlban:
{
"scripts": {
"test": "vitest --typecheck"
}
}
Most már futtathatod a típusellenőrzést:
npm run test
yarn test
pnpm run test
bun test
A Vitest a tsc --noEmit
vagy vue-tsc --noEmit
parancsot használja, a konfigurációdtól függően, így ezeket a szkripteket eltávolíthatod a pipeline-odból.