Ne pas utiliser as unknown as MyClass
23 mai 2023
TL;DR
Préférer les interfaces, l'abstraction et la séparation des responsabilités.
Contributeurs
Suxue Li, Julie Brunetto, Guillaume Moizan, Gauthier Fiorentino, Dorian De Rosa
Statut
Accepté
Contexte
On veut éviter d'avoir des casts en unknown
comme ça :
return {
envoyerAnalyticsPageVue: jest.fn(),
isAnalyticsAutorisé: jest.fn(() => false),
} as unknown as AnalyticsService;
Ces casts permettent de forcer le typage même lorsque l'objet ne respecte pas le contrat de la class, par exemple :
return {
envoyerAnalyticsPageVue: jest.fn(),
} as unknown as AnalyticsService;
// pas d'erreur de typage malgré le manque d'une méthode
return {
envoyerAnalyticsPageVue: jest.fn(),
isAnalyticsAutorisé: jest.fn(() => false),
truc: () => 'test'
} as unknown as AnalyticsService;
// pas d'erreur malgré la méthode superflue
return {
envoyerAnalyticsPageVue: jest.fn(),
isAnalyticsAutorisé: () => 'toto',
} as unknown as AnalyticsService;
// pas d'erreur malgré le prototype de la méthode incohérent avec son implémentation
Décision
Ne pas utiliser as unknown as MyClass
.
Conséquences
- Si la douleur vient de champs privés que typescript demande d'implémenter ==> passer par une interface n'exposant que les champs publics de la classe
class Toto {
public truc() {}
private machin() {}
}
// devient
interface Toto {
truc(): void;
}
class TotoImplementation implements Toto {
public truc() {}
private machin() {}
}
- Si la douleur vient du fait qu'on ne se sert que d'une partie de la classe ==> Séparer la classe en plusieurs classes à responsabilités uniques
class MonService {
public doStuff1() {}
public doStuff2() {}
}
// devient
class MonServiceStuff1 {
public execute() {}
}
class MonServiceStuff2 {
public execute() {}
}
- Si la douleur vient de l'utilisation d'une bibliothèque externe ==> Abstraire le typage avec uniquement les champs de la bibliothèque utilisés
function Truc(response: AxiosResponse<string>): void {}
// devient
type TrucResponse = { data: string }
function Truc(response: TrucResponse): void {}