Tipi di Test
Progetto Esempio
Vitest ti consente di scrivere test per i tuoi tipi, utilizzando le sintassi expectTypeOf
o assertType
. Per impostazione predefinita, tutti i test all'interno dei file *.test-d.ts
sono considerati test di tipo, ma puoi modificare questa impostazione tramite l'opzione di configurazione typecheck.include
.
Internamente, Vitest invoca tsc
o vue-tsc
, a seconda della tua configurazione, e analizza i risultati. Vitest visualizzerà anche eventuali errori di tipo rilevati nel tuo codice sorgente. Puoi disabilitare questa funzionalità con l'opzione di configurazione typecheck.ignoreSourceErrors
.
È importante notare che Vitest non esegue questi file; essi vengono solo analizzati staticamente dal compilatore. Ciò implica che se utilizzi un nome dinamico, test.each
o test.for
, il nome del test non verrà valutato e verrà mostrato così com'è.
WARNING
Prima di Vitest 2.1, la tua configurazione typecheck.include
sovrascriveva il pattern include
, impedendo l'esecuzione effettiva dei tuoi test di runtime, che venivano solo verificati a livello di tipi.
A partire da Vitest 2.1, se le tue configurazioni include
e typecheck.include
si sovrappongono, Vitest riporterà i test di tipo e i test di runtime come voci separate.
L'utilizzo delle opzioni della CLI, come --allowOnly
e -t
, è supportato anche per il controllo dei tipi.
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 }));
});
Qualsiasi errore di tipo generato all'interno di un file di test verrà trattato come un errore di test, permettendoti di utilizzare qualsiasi tecnica di tipizzazione desideri per testare i tipi del tuo progetto.
Puoi consultare un elenco dei matcher disponibili nella sezione API.
Lettura degli Errori
Se stai utilizzando l'API expectTypeOf
, fai riferimento alla documentazione di expect-type sui suoi messaggi di errore.
Quando i tipi non corrispondono, .toEqualTypeOf
e .toMatchTypeOf
utilizzano un tipo helper speciale per produrre messaggi di errore il più chiari possibile. Tuttavia, la loro comprensione richiede una certa sottigliezza. Poiché le asserzioni sono scritte in modo "fluente", l'errore dovrebbe essere sul tipo "atteso", non sul tipo "attuale" (expect<Actual>().toEqualTypeOf<Expected>()
). Ciò significa che gli errori di tipo possono essere un po' confusi; per questo motivo, questa libreria genera un tipo MismatchInfo
per cercare di rendere esplicita l'aspettativa. Ad esempio:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
Questa è un'asserzione che fallirà, poiché {a: 1}
ha tipo {a: number}
e non {a: string}
. Il messaggio di errore in questo caso sarà simile a:
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}>()
Nota che il vincolo di tipo riportato è un messaggio leggibile che specifica sia i tipi "attesi" che "attuali". Invece di prendere letteralmente la frase Types of property 'a' are incompatible // Type 'string' is not assignable to type "Expected: string, Actual: number"
, concentrati semplicemente sul nome della proprietà ('a'
) e sul messaggio: Expected: string, Actual: number
. Questo ti indicherà l'errore nella maggior parte dei casi. Per tipi estremamente complessi sarà ovviamente necessario un maggiore sforzo per il debug e potrebbero richiedere qualche sperimentazione. Per favore, segnala un problema se i messaggi di errore sono effettivamente fuorvianti.
I metodi toBe...
(come toBeString
, toBeNumber
, toBeVoid
ecc.) falliscono risolvendo a un tipo non richiamabile quando il tipo Actual
sotto test non corrisponde. Ad esempio, il fallimento per un'asserzione come expectTypeOf(1).toBeString()
sarà simile a:
test/test.ts:999:999 - error TS2349: This expression is not callable.
Type 'ExpectString<number>' has no call signatures.
999 expectTypeOf(1).toBeString()
~~~~~~~~~~
La parte This expression is not callable
non è molto utile; l'errore significativo è la riga successiva: Type 'ExpectString<number> has no call signatures
. Questo significa essenzialmente che hai passato un numero ma hai affermato che dovrebbe essere una stringa.
Se TypeScript aggiungesse il supporto per i "throw" types, questi messaggi di errore potrebbero essere migliorati significativamente. Fino ad allora, richiederanno un certo sforzo per essere compresi.
Oggetti "attesi" concreti vs argomenti di tipo
I messaggi di errore per un'asserzione come questa:
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' });
Saranno meno utili rispetto a un'asserzione come questa:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
Questo perché il compilatore TypeScript deve inferire l'argomento di tipo per lo stile .toEqualTypeOf({a: ''})
, e questa libreria può solo contrassegnarlo come un fallimento confrontandolo con un tipo Mismatch
generico. Quindi, dove possibile, usa un argomento di tipo piuttosto che un tipo concreto per .toEqualTypeOf
e toMatchTypeOf
. Se è molto più conveniente confrontare due tipi concreti, puoi usare typeof
:
const one = valueFromFunctionOne({ some: { complex: inputs } });
const two = valueFromFunctionTwo({ some: { other: inputs } });
expectTypeOf(one).toEqualTypeof<typeof two>();
Se trovi difficile utilizzare l'API expectTypeOf
e comprendere gli errori, puoi sempre usare l'API più semplice assertType
:
const answer = 42;
assertType<number>(answer);
// @ts-expect-error answer is not a string
assertType<string>(answer);
TIP
Quando usi la sintassi @ts-expect-error
, potresti voler assicurarti di non aver commesso un errore di battitura. Puoi farlo includendo i tuoi file di tipo nell'opzione di configurazione test.include
, in modo che Vitest esegua effettivamente questi test e fallisca con un ReferenceError
.
Questo test passerà, perché si aspetta un errore, ma la parola "answer" ha un errore di battitura, quindi si tratta di un falso positivo:
// @ts-expect-error answer is not a string
assertType<string>(answr); //
Esecuzione del Controllo dei Tipi
Per abilitare il controllo dei tipi, aggiungi semplicemente il flag --typecheck
al tuo comando Vitest in package.json
:
{
"scripts": {
"test": "vitest --typecheck"
}
}
Ora puoi eseguire il controllo dei tipi:
npm run test
yarn test
pnpm run test
bun test
Vitest utilizza tsc --noEmit
o vue-tsc --noEmit
, a seconda della tua configurazione, quindi puoi rimuovere questi script dalla tua pipeline.