TypeScript utility types for Material UI component development and React ecosystem.
npx @tessl/cli install tessl/npm-mui--types@7.4.0@mui/types provides essential TypeScript utility types and interfaces specifically designed for Material UI components and the broader React ecosystem. It includes advanced type manipulation utilities, overridable component interfaces, prop injection patterns, and string union generation helpers that enable robust type safety and component composition patterns.
npm install @mui/typesimport {
DistributiveOmit,
OverridableComponent,
OverridableTypeMap,
PropInjector,
Simplify,
expectType
} from "@mui/types";For CommonJS:
const {
DistributiveOmit,
OverridableComponent,
PropInjector
} = require("@mui/types");import {
OverridableComponent,
OverridableTypeMap,
DistributiveOmit,
Simplify
} from "@mui/types";
// Define a component with overridable root element
interface ButtonTypeMap extends OverridableTypeMap {
props: {
variant?: "contained" | "outlined" | "text";
disabled?: boolean;
};
defaultComponent: "button";
}
// Create an overridable component type
const Button: OverridableComponent<ButtonTypeMap> = {} as any;
// Usage with default component (button)
<Button variant="contained" disabled onClick={() => {}} />
// Usage with custom component (a)
<Button component="a" href="/home" variant="outlined" />
// Type utilities
type CleanProps = DistributiveOmit<{ a: string; b: number; c: boolean }, "b" | "c">;
// Result: { a: string }
type SimpleType = Simplify<{ a: string } & { b: number }>;
// Result: { a: string; b: number }@mui/types is built around several key patterns:
component prop pattern allowing flexible component compositionCore TypeScript utilities for advanced type operations and manipulation.
/**
* Remove properties K from T, distributive for union types
*/
type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;
/**
* Like T & U, but using value types from U where properties overlap
*/
type Overwrite<T, U> = DistributiveOmit<T, keyof U> & U;
/**
* Simplifies display of a type without modifying it
*/
type Simplify<T> = T extends Function ? T : { [K in keyof T]: T[K] };
/**
* Changes properties K from T to required
*/
type PartiallyRequired<T, K extends keyof T> = DistributiveOmit<T, K> & {
[P in K]-?: T[P];
};
/**
* Generate string literal types with default record T and override record U
*/
type OverridableStringUnion<T extends string | number, U = {}> = GenerateStringUnion<
Overwrite<Record<T, true>, U>
>;Advanced component patterns enabling the component prop for flexible component composition.
/**
* A component whose root component can be controlled via a component prop
*/
interface OverridableComponent<M extends OverridableTypeMap> {
<C extends React.ElementType>(
props: {
/**
* The component used for the root node.
* Either a string to use a HTML element or a component.
*/
component: C;
} & OverrideProps<M, C>,
): React.JSX.Element | null;
(props: DefaultComponentProps<M>): React.JSX.Element | null;
propTypes?: any;
}
/**
* Base interface for overridable component type mapping
*/
interface OverridableTypeMap {
props: {};
defaultComponent: React.ElementType;
}
/**
* Props when component={Component} is used
*/
type OverrideProps<
M extends OverridableTypeMap,
C extends React.ElementType
> = (
& BaseProps<M>
& DistributiveOmit<React.ComponentPropsWithRef<C>, keyof BaseProps<M>>
);
/**
* Props when component={Component} is NOT used
*/
type DefaultComponentProps<M extends OverridableTypeMap> =
& BaseProps<M>
& DistributiveOmit<React.ComponentPropsWithRef<M['defaultComponent']>, keyof BaseProps<M>>;
/**
* Props defined on the component from the type map
*/
type BaseProps<M extends OverridableTypeMap> = M['props'];Higher-order component utilities for type-safe prop injection and manipulation.
/**
* Ensures overlapping properties between T and U have non-conflicting value types
*/
type ConsistentWith<DecorationTargetProps, InjectedProps> = {
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
? InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: InjectedProps[P]
: DecorationTargetProps[P];
};
/**
* A function that takes {component} and returns a component that passes along
* all props to {component} except the {InjectedProps} and accepts additional {AdditionalProps}
*/
type PropInjector<InjectedProps, AdditionalProps = {}> = <
C extends React.JSXElementConstructor<ConsistentWith<React.ComponentProps<C>, InjectedProps>>,
>(
component: C,
) => React.JSXElementConstructor<
DistributiveOmit<
React.JSX.LibraryManagedAttributes<C, React.ComponentProps<C>>,
keyof InjectedProps
> &
AdditionalProps
>;Tools for type-level testing and validation in TypeScript projects.
/**
* Conditional type for exact type equality checking
*/
type IfEquals<T, U, Y = unknown, N = never> =
(<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? Y : N;
/**
* Issues a type error if Expected is not identical to Actual
* @param actual - Value to test, should be typeof value statement
*/
declare function expectType<Expected, Actual>(
actual: IfEquals<Actual, Expected, Actual>,
): void;import { OverridableComponent, OverridableTypeMap } from "@mui/types";
// Define your component's type map
interface MyComponentTypeMap extends OverridableTypeMap {
props: {
color?: "primary" | "secondary";
size?: "small" | "medium" | "large";
};
defaultComponent: "div";
}
// Use the type in your component definition
const MyComponent: OverridableComponent<MyComponentTypeMap> =
React.forwardRef((props, ref) => {
const { component: Component = "div", color, size, ...other } = props;
return <Component ref={ref} {...other} />;
});
// Usage
<MyComponent color="primary" /> // renders as div
<MyComponent component="section" color="secondary" /> // renders as section
<MyComponent component="a" href="/link" color="primary" /> // renders as anchor with hrefimport { PropInjector, ConsistentWith } from "@mui/types";
interface ThemeProps {
theme: {
primaryColor: string;
backgroundColor: string;
};
}
// Create a HOC that injects theme props
const withTheme: PropInjector<ThemeProps> = (Component) => {
return (props) => {
const theme = {
primaryColor: "#1976d2",
backgroundColor: "#ffffff",
};
return <Component {...props} theme={theme} />;
};
};
// Use with any component
const MyButton = (props: { label: string; theme: ThemeProps["theme"] }) => (
<button style={{ color: props.theme.primaryColor }}>
{props.label}
</button>
);
const ThemedButton = withTheme(MyButton);
// Usage: <ThemedButton label="Click me" /> (theme is automatically injected)import { DistributiveOmit, Overwrite, Simplify, PartiallyRequired } from "@mui/types";
interface User {
id: number;
name: string;
email: string;
isActive: boolean;
}
// Remove sensitive fields for public API
type PublicUser = DistributiveOmit<User, "email" | "isActive">;
// Result: { id: number; name: string }
// Override specific properties
type UserWithStringId = Overwrite<User, { id: string }>;
// Result: { id: string; name: string; email: string; isActive: boolean }
// Simplify complex intersection types
type ComplexType = { a: string } & { b: number } & { c: boolean };
type SimpleType = Simplify<ComplexType>;
// Result: { a: string; b: number; c: boolean }
// Make specific properties required
type UserWithRequiredEmail = PartiallyRequired<Partial<User>, "email">;
// Result: { id?: number; name?: string; email: string; isActive?: boolean }import { expectType, IfEquals } from "@mui/types";
// Test exact type equality
const value = "hello";
expectType<string, typeof value>(value); // ✓ passes
// expectType<number, typeof value>(value); // ✗ type error
// Conditional type checking
type IsString<T> = IfEquals<T, string, "yes", "no">;
type Test1 = IsString<string>; // "yes"
type Test2 = IsString<number>; // "no"