TypeScript Mapped Types & Utility Collection
react-redux-typescript provides a robust collection of advanced TypeScript utility types, primarily focusing on 'Mapped Types' for complex object and key manipulation. As of version 3.11.0, it offers types like `DiffKeys`, `Omit`, `Assign`, `Overwrite`, `DeepReadonly`, `Optional`, `Required`, `Mutable`, and `UnionToIntersection`. It also includes a utility function `getReturnOfExpression` for inferring function return types. The library is actively maintained with frequent minor releases, though its name can be misleading as the React/Redux-specific parts (re-exports from `typesafe-actions`) are deprecated and slated for removal in future major versions. A key differentiator is its commitment to thorough type correctness testing, zero third-party runtime dependencies for its core utility types, and providing separate bundles for various module workflows (CommonJS, ES Module).
Common errors
-
TS2345: Argument of type 'string' is not assignable to parameter of type '{ theme: "dark" | "light"; notifications: boolean; }'.cause Attempting to assign a value to a deeply `Readonly` type, which prevents modification of nested properties.fixEnsure that if you are using types like `DeepReadonly<T>`, you do not attempt to modify any properties, including nested ones. Create a mutable copy if modification is necessary. -
TypeError: Cannot read properties of undefined (reading 'OmitKeys')
cause Attempting to use CommonJS `require()` syntax (e.g., `const { OmitKeys } = require('react-redux-typescript');`) in an ES Module context or when the package's `exports` map doesn't permit it.fixUse ES Module import syntax: `import { OmitKeys } from 'react-redux-typescript';` Ensure your `tsconfig.json` `module` and `moduleResolution` settings are appropriate for your environment (e.g., 'NodeNext' or 'Bundler'). -
TS2344: Type 'string | number' does not satisfy the constraint 'keyof T'.
cause Using `Omit<T, K>` or `Pick<T, K>` with a key `K` that is not a valid key of type `T`.fixVerify that the keys you are attempting to `Omit` or `Pick` (`K`) are indeed present in the base type `T`. TypeScript's strictness prevents operating on non-existent keys, which helps catch typos.
Warnings
- deprecated The 'Redux Typesafe Actions' utilities (e.g., createAction, getType, isActionOf) re-exported from `typesafe-actions` are deprecated and will be removed in the next major release. Users should migrate to importing these directly from `typesafe-actions`.
- deprecated The `Falsey` type alias was deprecated in v3.9.0 and replaced with `Falsy`. While `Falsey` is kept for backward compatibility, it is recommended to update to the new alias.
- gotcha The package name `react-redux-typescript` is largely historical. Most of its current utility types are general-purpose TypeScript mapped types, with the React/Redux-specific re-exports being deprecated. This can be misleading for new users expecting only React/Redux-specific functionality.
- breaking An issue with TypeScript v3.5's native `Omit` implementation caused `react-redux-typescript` to revert to an older, custom `Omit` implementation in v3.6.1 to ensure correctness. While fixed internally, users should be aware of potential subtle differences or unexpected type inference if upgrading from very old versions or encountering edge cases with specific TS versions.
Install
-
npm install react-redux-typescript -
yarn add react-redux-typescript -
pnpm add react-redux-typescript
Imports
- Omit
import Omit from 'react-redux-typescript';
import { Omit } from 'react-redux-typescript'; - Assign
const { Assign } = require('react-redux-typescript');import { Assign } from 'react-redux-typescript'; - getReturnOfExpression
import * as RRT from 'react-redux-typescript'; const func = RRT.getReturnOfExpression;
import { getReturnOfExpression } from 'react-redux-typescript'; - DeepReadonly
import { Readonly } from 'react-redux-typescript';import { DeepReadonly } from 'react-redux-typescript';
Quickstart
import { Omit, Assign, DeepReadonly } from 'react-redux-typescript';
interface UserProfile {
id: string;
name: string;
email: string;
settings: {
theme: 'dark' | 'light';
notifications: boolean
};
createdAt: Date;
}
interface PartialUpdate {
name?: string;
email?: string;
updatedAt: Date;
}
// Example 1: Omit properties from a type
type UserWithoutSensitiveInfo = Omit<UserProfile, 'email' | 'createdAt'>;
// Expected: { id: string; name: string; settings: { theme: 'dark' | 'light'; notifications: boolean }; }
const user1: UserWithoutSensitiveInfo = {
id: '123',
name: 'Alice',
settings: { theme: 'dark', notifications: true }
};
// Example 2: Assign (merge) properties, overwriting if they exist
type MergedProfile = Assign<UserProfile, PartialUpdate>;
// Expected: { id: string; name: string; email: string; settings: { theme: 'dark' | 'light'; notifications: boolean }; createdAt: Date; updatedAt: Date; }
const user2: MergedProfile = {
id: '456',
name: 'Bob',
email: 'bob@example.com',
settings: { theme: 'light', notifications: false },
createdAt: new Date(),
updatedAt: new Date()
};
// Example 3: Make all properties and nested properties readonly
type ReadonlyUserProfile = DeepReadonly<UserProfile>;
const readonlyUser: ReadonlyUserProfile = {
id: '789',
name: 'Charlie',
email: 'charlie@example.com',
settings: {
theme: 'light',
notifications: true
},
createdAt: new Date()
};
// readonlyUser.name = 'David'; // This line would cause a TypeScript error
console.log('User without sensitive info:', user1);
console.log('Merged profile:', user2);
console.log('Readonly user (check types):', readonlyUser);