
Naviguer dans la Flexibilité du Monde Réel avec TypeScript
Dans le domaine dynamique du développement logiciel, il n’est pas rare de rencontrer du code fonctionnel mais rigide. Récemment, je suis tombé sur une implémentation TypeScript qui bien qu’efficace, offrait peu de possibilités d’adaptation. Dans cet article de blog, je vous guiderai à travers mon parcours pour résoudre ce problème en adoptant une solution plus dynamique en utilisant le modèle Map.
Dévoiler la Structure Rigide
Face à ce type particulier de TypeScript, j’ai constaté sa rigidité :
// FinalResponse.ts
import { Reaction } from './Reaction'
export type FinalResponse = {
totalScore: number
headingsPenalty: number
sentencesPenalty: number
charactersPenalty: number
wordsPenalty: number
headings: string[]
sentences: string[]
words: string[]
links: { href: string; text: string }[]
exceeded: {
exceededSentences: string[]
repeatedWords: { word: string; count: number }[]
}
reactions: {
likes: Reaction
unicorns: Reaction
explodingHeads: Reaction
raisedHands: Reaction
fire: Reaction
}
}
Cette configuration reposait sur un type Reaction
compagnon :
// Reaction.ts
export type Reaction = {
count: number
percentage: number
}
Et elle était intégrée dans la fonction suivante :
// calculator.ts
export const calculateScore = (
headings: string[],
sentences: string[],
words: string[],
totalPostCharactersCount: number,
links: { href: string; text: string }[],
reactions: {
likes: Reaction
unicorns: Reaction
explodingHeads: Reaction
raisedHands: Reaction
fire: Reaction
},
): FinalResponse => {
// Logique de calcul du score...
}
Le Dilemme de l’Inflexibilité
Imaginez le scénario où vous devez intégrer une nouvelle réaction (par exemple, des cœurs ou des applaudissements). Avec la structure existante, introduire ce changement apparemment mineur implique :
- De remanier le fichier
FinalResponse.ts
. - De mettre à jour le type
Reaction.ts
si nécessaire. - De modifier la fonction
calculateScore
. - De redéfinir potentiellement d’autres sections dépendantes de l’application.
Une telle étroite interconnexion empêche des changements simples et directs, augmentant le potentiel d’erreur à travers plusieurs fichiers.
Une Réorchestration Dynamique
En repensant l’organisation avec une approche flexible et réutilisable, j’ai proposé une redéfinition élégante :
// FinalResponse.ts
import { Reaction } from './Reaction'
export type ReactionMap = Record<string, Reaction>
export type FinalResponse = {
totalScore: number
headingsPenalty: number
sentencesPenalty: number
charactersPenalty: number
wordsPenalty: number
headings: string[]
sentences: string[]
words: string[]
links: { href: string; text: string }[]
exceeded: {
exceededSentences: string[]
repeatedWords: { word: string; count: number }[]
}
reactions: ReactionMap
}
Analyse Detaillée:
ReactionMap
: UtiliseRecord<string, Reaction>
pour permettre n’importe quelle chaîne comme clé valide avec une valeur de typeReaction
.FinalResponse
: Transforme le champreactions
enReactionMap
, permettant l’ajout dynamique sans fouiller dans plusieurs fichiers.
Plaidoyer pour un Code Plus Propre
La transformation dans calculator.ts
témoigne d’un codage plus propre et plus adaptable :
// calculator.ts
export const calculateScore = (
headings: string[],
sentences: string[],
words: string[],
totalPostCharactersCount: number,
links: { href: string; text: string }[],
reactions: ReactionMap,
): FinalResponse => {
// Logique de calcul du score...
}
Équilibrer Flexibilité et Contrôle
Tandis que la nouvelle flexibilité offre de vastes possibilités, elle frôle également le risque d’un usage abusif - des réactions non vérifiées pourraient ouvrir la voie à des chaînes arbitraires.
Trouver un Équilibre Sécurisant
Raffiner la solution en limitant les réactions à des valeurs autorisées spécifiques rehausse la sécurité et la cohérence :
// FinalResponse.ts
import { Reaction } from './Reaction'
type AllowedReactions =
| 'likes'
| 'unicorns'
| 'explodingHeads'
| 'raisedHands'
| 'fire'
export type ReactionMap = {
[key in AllowedReactions]: Reaction
}
export type FinalResponse = {
totalScore: number
headingsPenalty: number
sentencesPenalty: number
charactersPenalty: number
wordsPenalty: number
headings: string[]
sentences: string[]
words: string[]
links: { href: string; text: string }[]
exceeded: {
exceededSentences: string[]
repeatedWords: { word: string; count: number }[]
}
reactions: ReactionMap
}
Envisager le Nouveau Paradigme
Conclusion de l’Aventure
Voici un procédé qui harmonise flexibilité et contrôle :
- Flexibilité : Simplifie l’ajout de nouvelles réactions en modifiant uniquement le type
AllowedReactions
. - Contrôle : L’exploitation d’un type union protège contre l’inclusion de réactions invalides.
Cette méthodologie s’aligne avec le principe Ouvert/Fermé, permettant l’extension des fonctionnalités sans modifier les structures fondamentales. Grâce à ce modèle innovant, nous étendons les types de réactions sans effort tout en maintenant une gouvernance sur les actions permises.