This TypeScript implementation showcases a refactoring process to improve flexibility and maintainability. Let's rephrase it for clarity and improved flow.
During a recent project, I encountered a TypeScript implementation that, while functional, lacked flexibility. This post details the problem, its solution using the Map pattern, and how this approach enhances code maintainability.
Table of Contents
1. The Initial Problem
The original code used these TypeScript types:
<code class="language-typescript">// Reaction.ts export type Reaction = { count: number; percentage: number; }; // 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; }; };</code>
This FinalResponse
type was used in a scoring function:
<code class="language-typescript">// calculator.ts export const calculateScore = ( // ... input parameters ... reactions: { likes: Reaction; unicorns: Reaction; explodingHeads: Reaction; raisedHands: Reaction; fire: Reaction; }, ): FinalResponse => { // Score calculation logic... };</code>
2. Limitations of the Original Approach
Adding a new reaction required modifications across multiple files (FinalResponse.ts
, calculator.ts
, and potentially others). This tight coupling increased the risk of errors and made the code less maintainable.
3. Implementing the Map Pattern Solution
To address this, a more dynamic approach using a Map
-like structure was implemented:
<code class="language-typescript">// FinalResponse.ts import { Reaction } from './Reaction'; type AllowedReactions = | 'likes' | 'unicorns' | 'explodingHeads' | 'raisedHands' | 'fire'; export type ReactionMap = { [key in AllowedReactions]: Reaction; }; export type FinalResponse = { // ... other properties ... reactions: ReactionMap; };</code>
4. Clean Code Implementation
The calculateScore
function now uses the ReactionMap
:
<code class="language-typescript">// calculator.ts export const calculateScore = ( // ... input parameters ... reactions: ReactionMap, ): FinalResponse => { // Score calculation logic... };</code>
5. Enforcing Type Safety with Allowed Reactions
While the ReactionMap
offers flexibility, it's crucial to maintain type safety. The AllowedReactions
union type restricts the allowed reaction keys, preventing the addition of arbitrary reactions.
6. Visual Comparison
7. Conclusion
This refactored approach balances flexibility and type safety. Adding new reactions only requires updating the AllowedReactions
type, significantly improving maintainability and reducing the risk of errors compared to the original tightly coupled design. The use of a Record
type effectively emulates the benefits of a map without the runtime overhead of a Map
object.
The above is the detailed content of Dont use TypeScript types like this. Use Map Pattern instead. For more information, please follow other related articles on the PHP Chinese website!