- Published on
How to Explicitly Set a New Property on `window` in TypeScript
- Authors
- Name
- Ripal & Zalak
When working with web applications, there are times when you may need to add custom properties to the global window
object. While this is straightforward in plain JavaScript, TypeScript’s strict typing system introduces additional challenges. This article explains how to explicitly set a new property on window
in TypeScript while maintaining type safety and avoiding common pitfalls.
Why TypeScript Complains
In TypeScript, the window
object is typed as the Window
interface, which contains predefined properties and methods. When you attempt to add a custom property (e.g., window.myProperty
), TypeScript raises an error because the property is not defined on the Window
interface.
declare global {
interface Window {
myProperty: string
}
}
window.myProperty = 'Hello, world!' // ✅ No errors
Common Solutions
Window
Interface
1. Extend the The most type-safe way to add properties to window
is by extending the Window
interface using declaration merging. Here’s how:
// Create a global declaration
declare global {
interface Window {
myCustomProperty: string
}
}
// Assign a value to the custom property
window.myCustomProperty = 'This is a custom property'
console.log(window.myCustomProperty) // Output: This is a custom property
This approach ensures:
- Type Safety: TypeScript knows about the new property, enabling autocompletion and error checking.
- Global Scope: The property is available wherever
window
is used in the project.
2. Using Type Assertions
If you want a quick and less strict solution, you can use type assertions to temporarily bypass TypeScript’s type checks:
;(window as any).myCustomProperty = 'This is a quick hack'
console.log((window as any).myCustomProperty)
While this works, it has some drawbacks:
- Lack of Type Safety: No autocompletion or error checking for the custom property.
- Risk of Bugs: Potential runtime errors if the property is accessed incorrectly.
This method should be used sparingly and is best suited for prototyping or temporary fixes.
3. Create a Custom Interface
For better modularity, you can define a custom interface and cast window
to that interface:
interface MyWindow extends Window {
myNamespace: {
someFunction: () => void
}
}
declare let window: MyWindow
window.myNamespace = {
someFunction: () => {
console.log('Hello from myNamespace')
},
}
window.myNamespace.someFunction() // Output: Hello from myNamespace
This approach is particularly useful when dealing with complex objects or namespaces.
window['propertyName']
4. Use If you prefer not to modify TypeScript’s type definitions, you can use the index signature to add properties:
window['myDynamicProperty'] = 'Dynamic value'
console.log(window['myDynamicProperty']) // Output: Dynamic value
While this avoids TypeScript errors, it’s less elegant and doesn’t provide type safety.
Best Practices
- Avoid Overuse of Globals: Minimize the use of global properties to reduce the risk of conflicts and maintain modularity.
- Prefer Type-Safe Solutions: Extending the
Window
interface is the recommended approach for production code. - Document Custom Properties: Clearly document custom properties for team members and future maintainers.
Example: Redux DevTools Integration
A common use case for extending the window
object is enabling Redux DevTools in a TypeScript project:
declare global {
interface Window {
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose
}
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
This ensures TypeScript recognizes the Redux DevTools property while maintaining type safety.
Conclusion
Adding custom properties to the window
object in TypeScript requires careful consideration of type safety and maintainability. By extending the Window
interface or using other type-safe methods, you can enhance your project while leveraging TypeScript’s powerful features. Choose the approach that best fits your needs and coding standards.