When I load third-party scripts conditionally, especially only in production, it’s easy to think that a simple conditional statement will do the trick. However, I’ve learned that TypeScript can cause some unexpected behavior if the code isn’t written properly. Let me walk you through the potential issues I’ve faced and how I solved them.
Common Issue 1: Incorrect Type Inference
I’ve tried conditionally loading scripts like this:
scripts: [process.env.NODE_ENV === "production" && { src: "analytics.js" }];
Why This Didn’t Work:
TypeScript interpreted this as (boolean | object)[], which caused problems. The array contained false values (interpreted as boolean), leading to an incorrect type structure.
Common Issue 2: Empty Objects in Development
Another approach I tried was:
scripts: [process.env.NODE_ENV === "production" ? { src: "analytics.js" } : {}];
Why This Was a Problem:
In this case, I ended up with empty objects ({}) in the development environment. TypeScript then complained about missing required properties, which made the code harder to maintain.
The Correct Approach
I found a better way to handle this by using the spread operator with a ternary conditional. Here’s how I load the scripts conditionally while maintaining type integrity:
scripts: [
// Always loaded
{ src: "required-script.js" },
// Production-only scripts
...(process.env.NODE_ENV === "production"
? [
{
defer: true,
src: "analytics.js",
} as const,
{ src: "error-tracking.js" } as const,
]
: []),
];
Why This Works:
- Type Safety: Using
as constensures that TypeScript locks the object shape and prevents widening the types. - No Empty Objects: The spread operator ensures that the array only contains relevant scripts, preventing empty objects in development.
- Maintainable: This solution keeps my code clean and future-proof, especially when I need to add more scripts later.
- Clarity: There’s a clear separation between always-loaded and production-only scripts, which makes the code easier to maintain.
Use Cases for Conditional Script Loading
This approach works well for:
- Loading analytics tools (e.g., Google Tag Manager)
- A/B testing scripts
- Performance monitoring tools
- Any script that should only be included in production and not in development
Conclusion
By using the spread operator, ternary conditions, and as const, I’m able to load scripts conditionally without running into TypeScript issues. This approach keeps my codebase clean and maintainable, preventing unnecessary bugs down the line.