What is TS Reset?
TS Reset is an open-source TypeScript library created by Matt Pocock, the renowned TypeScript educator behind Total TypeScript. It functions as a "type reset" for your TypeScript compiler, similar to how CSS reset normalizes browser styles. When you add TS Reset to your project, it overrides certain default TypeScript type behaviors to provide more sensible, predictable, and safer type inference across your entire codebase.
The library targets specific areas where TypeScript's default type definitions produce results that don't match developer expectations. These aren't bugs in TypeScript, but rather design decisions made for various reasons that sometimes lead to less-than-ideal developer experiences. TS Reset provides opinionated overrides that make common operations behave more intuitively while maintaining type safety.
By importing TS Reset in a single file within your project, these improved typings automatically apply to all files in your codebase. This means you get better type inference for JSON parsing, array methods, storage APIs, and more, without needing to modify your existing code or add type annotations throughout your project. The library works as a type layer that sits between your code and the TypeScript compiler, automatically improving type inference without any changes to your runtime code or development workflow.
For teams building modern web applications with TypeScript, adopting TS Reset represents a straightforward way to improve code quality. The library is particularly valuable when combined with other web development best practices and works seamlessly with modern frameworks like Next.js, React, and Vue. If you're just getting started with TypeScript, consider pairing this guide with our JavaScript Reference Guide for a comprehensive foundation in modern JavaScript development.
Why Standard TypeScript Types Fall Short
To understand the value TS Reset provides, it's important to recognize where standard TypeScript types create friction in everyday development. The default TypeScript library definitions were designed to be broadly applicable across many use cases, which sometimes means they prioritize edge-case compatibility over developer ergonomics.
JSON.parse Returns any
When you parse a JSON string in TypeScript, the return type is any, which effectively disables type checking for that value. While this reflects the reality that TypeScript cannot know at compile time what structure the parsed JSON will have, it creates dangerous situations where typos and type mismatches go unnoticed.
const data = JSON.parse('{"name": "John", "age": 30}');
// data is typed as `any`
console.log(data.name.toUpperCase()); // No error shown
console.log(data.address.city); // No error, but undefined at runtime
Array Methods Don't Narrow Types
Using .filter(Boolean) should remove falsy values from an array, but standard TypeScript types don't make this inference, leaving you with the same union type you started with.
const mixed = [1, 2, undefined, 3, null, 4];
const filtered = mixed.filter(Boolean);
// filtered is still (number | undefined | null)[]
const first: number = filtered[0]; // Error, but logically should work
Fetch API Returns any
When you call response.json(), TypeScript returns any, which defeats type safety for API responses. This is particularly problematic in modern applications that rely heavily on REST or GraphQL APIs.
fetch('/api/users/1')
.then(res => res.json())
.then(data => {
// data is `any` - no type safety
console.log(data.name.toUpperCase()); // No type checking
});
These issues represent common pain points that many TypeScript developers work around with type assertions or disable strict type checking entirely. TS Reset addresses these patterns with carefully designed type improvements that match developer expectations.
TS Reset addresses common TypeScript pain points with carefully designed type improvements
JSON.parse Returns Unknown
Instead of returning `any`, JSON.parse now returns `unknown`, requiring explicit type narrowing before use.
Better Array Methods
.filter(Boolean) properly narrows array types, and .includes() works smoothly with readonly arrays.
Safer Fetch API
Response.json() returns `unknown` instead of `any`, forcing type validation for API responses.
Storage API Safety
localStorage and sessionStorage return `unknown` for undefined keys, preventing implicit type assumptions.
Set and Map Improvements
Set.has() and Map.has() are less strict, making common patterns more ergonomic.
Array.isArray Enhancement
Properly removes `any[]` from union types when checking if something is an array.
Installation and Setup
Getting started with TS Reset requires just a few steps.
Step 1: Install the Package
npm install -D @total-typescript/ts-reset
Or with yarn:
yarn add -D @total-typescript/ts-reset
Step 2: Create reset.d.ts
Create a file named reset.d.ts in your source directory with this content:
import "@total-typescript/ts-reset";
Place this file in your src directory or wherever your TypeScript entry point can find it. The file must be included in your tsconfig.json via the include array or files array.
Step 3: Verify tsconfig.json
Ensure your moduleResolution is set to NodeNext, Node16, or Bundler:
{
"compilerOptions": {
"moduleResolution": "NodeNext"
}
}
Step 4: Add to Your Build Process
Import the reset file in your TypeScript entry point if needed. For most projects, simply including it in your source directory is sufficient. Run tsc to verify no errors appear, and start seeing improved type inference immediately.
For projects using DOM APIs like localStorage, also import the DOM-specific rules:
import "@total-typescript/ts-reset/dom";
If you encounter any issues, check that your TypeScript version is 4.0 or higher and that your build tool supports the module resolution mode you've selected.
Selective Rule Imports
While importing the full TS Reset library provides all recommended improvements, you can also selectively import only the rules you need. This approach is useful if you want to adopt TS Reset incrementally or only need specific type improvements in certain parts of your codebase.
Available Selective Imports
@total-typescript/ts-reset/json-parse- Makes JSON.parse return unknown@total-typescript/ts-reset/fetch- Makes fetch().json() return unknown@total-typescript/ts-reset/filter-boolean- Makes .filter(Boolean) filter out falsy values@total-typescript/ts-reset/array-includes- Makes .includes on readonly arrays less strict@total-typescript/ts-reset/set-has- Makes Set.has() less strict@total-typescript/ts-reset/map-has- Makes Map.has() less strict@total-typescript/ts-reset/array-is-array- Improves Array.isArray() typing@total-typescript/ts-reset/dom- Makes localStorage and sessionStorage safer
Combining Selective Imports
You can combine multiple selective imports in your reset.d.ts file to create a custom configuration:
// Only the rules you want
import "@total-typescript/ts-reset/json-parse"
import "@total-typescript/ts-reset/fetch"
import "@total-typescript/ts-reset/filter-boolean"
When to Use Selective vs Full Import
Use selective imports when:
- You're adopting TS Reset gradually across a large codebase
- You only need specific type improvements
- You want to measure the impact of each rule individually
- Some rules don't apply to your project (e.g., no DOM APIs in a Node.js service)
Use full import when:
- Starting a new project with full TS Reset benefits
- You want consistent type behavior across all supported operations
- Your team is committed to adopting the improved types
The full import provides the most comprehensive type safety improvements and is recommended for new projects. Selective imports offer flexibility for incremental adoption in larger codebases.
JSON.parse: Before and After
Without TS Reset:
const data = JSON.parse('{"name": "John"}');
// data is `any` - no type safety
console.log(data.name.toUpperCase()); // No error, but could fail
With TS Reset:
const data = JSON.parse('{"name": "John"}');
// data is `unknown`
// Must narrow type first - error if you try to access properties directly
if (isUser(data)) {
console.log(data.name.toUpperCase()); // Works after type guard
}
When to Use TS Reset
TS Reset is designed specifically for application code rather than library or package development. This distinction is important because each rule modifies the global TypeScript scope, and the implications differ significantly between these two use cases.
For Applications
When you're building an application, you control the entire codebase. You can adopt TS Reset, verify that all your code works correctly with the new type behaviors, and maintain consistency throughout your project. The global effect is beneficial because you're making an intentional choice that affects only your project. Applications built with modern JavaScript frameworks can benefit from TS Reset's improved type inference without worrying about downstream effects.
For Libraries
For libraries or npm packages, the situation is different. Your package's types become part of your users' projects, and forcing global type modifications could conflict with other libraries or their own TS Reset usage. If you're building a library, it's better to rely on standard TypeScript types or create explicit type utilities within your package that provide the behavior you want without modifying the global scope.
Why Global Type Changes Are Problematic for Libraries
When a library modifies global types, those modifications affect every file in any project that uses your library. This can lead to unexpected behavior when users combine multiple libraries that each try to modify global types. TypeScript's declaration merging provides some isolation, but the potential for conflicts increases as more libraries make global modifications.
Additionally, library users may have intentionally chosen to use (or not use) TS Reset in their own projects. Forcing this choice upon them removes their agency and can create confusing type errors when their expectations don't match your library's type modifications.
The Bottom Line
Use TS Reset in applications where you want comprehensive type improvements. Avoid using TS Reset in libraries where you need to maintain type compatibility with your users' projects.
Adopting TS Reset in Existing Projects
Introducing TS Reset to an existing codebase requires some consideration, especially if your project currently relies on the default TypeScript behaviors that TS Reset modifies. The transition is generally smooth because TS Reset's changes make types more strict, which means existing code that worked with any will now require type narrowing.
Getting Started
- Install TS Reset and create your
reset.d.tsfile - Run your TypeScript compiler to see what errors appear
- Address type errors related to code relying on implicit
anytypes - Add proper type guards or type assertions where needed
Incremental Adoption Strategy
Use selective imports to adopt rules gradually:
// Only the rules you want to adopt first
import "@total-typescript/ts-reset/json-parse"
import "@total-typescript/ts-reset/fetch"
Add more rules once your team is comfortable with the changes. This phased approach allows your team to adjust to the new type behaviors gradually while addressing issues systematically.
Common Adjustments
- Add type guards for JSON parsing: Create reusable type guard functions for commonly parsed data structures
- Use discriminated unions for API responses: Define explicit union types that represent each possible response shape
- Write proper type narrowing logic: Replace type assertions with runtime validation where possible
Making the Transition Smooth for Teams
For larger teams, consider the following approaches:
- Start with a single team or feature: Pilot TS Reset on a smaller part of your codebase before rolling out globally
- Document type guard patterns: Create examples showing how to properly narrow types in your codebase
- Set up pair programming sessions: Help team members understand the benefits of stricter types
- Create a migration guide: Document the specific changes needed for common patterns in your codebase
For projects with extensive any types or type assertions, you might find that TS Reset surfaces areas where type coverage was incomplete. This is valuable feedback that helps you improve your codebase's type safety over time. To further strengthen your testing practices, consider exploring our guide on testing Next.js apps with Jest to ensure comprehensive type safety across your entire application.
Best Practices for Type Safety
While TS Reset provides improved type inference, it works best as part of a comprehensive type safety strategy. Here are practices that maximize the benefits of TS Reset in your projects.
Write Type Guards
Create reusable type guard functions for commonly parsed data structures:
interface User {
id: number;
name: string;
email: string;
}
function isUser(data: unknown): data is User {
return (
typeof data === 'object' &&
data !== null &&
'id' in data &&
'name' in data &&
'email' in data &&
typeof data.id === 'number' &&
typeof data.name === 'string' &&
typeof data.email === 'string'
);
}
Type guards combine runtime validation with compile-time type narrowing for maximum safety.
Use Discriminated Unions
For API responses with different shapes, use discriminated unions:
type APIResponse =
| { status: 'success'; data: User; timestamp: Date }
| { status: 'error'; message: string; code: number }
| { status: 'loading'; progress: number }
function handleResponse(response: APIResponse) {
switch (response.status) {
case 'success':
// TypeScript knows response.data is User
console.log(response.data.name);
break;
case 'error':
// TypeScript knows response.message is string
console.error(response.message);
break;
}
}
Combine with Modern TypeScript Features
TS Reset works well with TypeScript's newer features:
- Template literal types: For precise string value types
satisfiesoperator: Validate types without widening- Const assertions: Preserve literal types throughout your code
- Generic type parameters: Create reusable type-safe utilities
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
} as const;
type Config = typeof config;
// Config is precisely typed with literal values
By combining TS Reset with these practices, you create a robust type safety foundation that catches errors early and makes refactoring safer. For teams working with date handling in TypeScript, our guide on handling date strings in TypeScript provides additional patterns for maintaining type safety with temporal data.
Common Questions About TS Reset
Conclusion
TS Reset represents a thoughtful approach to improving TypeScript's developer experience by addressing common pain points in the standard library types. By making JSON parsing, array methods, and storage APIs behave more intuitively, it helps developers write safer code with less friction.
The library's opinionated type changes encourage better practices like writing type guards and properly validating data shapes. While this requires some adjustment if you're used to relying on any, the result is more robust, maintainable TypeScript code that catches errors at compile time rather than runtime.
For application developers looking to improve their TypeScript setup, TS Reset offers a low-effort, high-impact enhancement that pays dividends in code quality. The selective import system allows gradual adoption, and the library's focus on application code ensures it won't cause issues for library authors.
Consider adding TS Reset to your next web development project to experience the benefits of improved type inference and stronger compile-time safety. Combined with modern JavaScript frameworks and a comprehensive type safety strategy, TS Reset helps teams build more reliable applications.