How to fix Object literal may only specify known properties, and 'name' does not exist in type 'T'. ts(2353) in TypeScript
TS2353 fires when an object literal has a property not in the target type. Fix the typo, widen the type, or assert with 'as'.
Quick fix
Fixes Object literal may only specify known properties, and 'name' does not exist in type 'T'. ts(2353)
interface User {
name: string;
age: number;
}
// ERROR: 'email' doesn't exist in User
function saveUser(user: User) {}
saveUser({ name: 'John', age: 30, email: 'john@example.com' });
// Object literal may only specify known properties...
// FIX: Remove the extra property
saveUser({ name: 'John', age: 30 });
// OR if 'email' should be included, update the interface:
interface User {
name: string;
age: number;
email?: string; // Make it optional
}- Remove or rename the extra properties
- Use a type assertion to bypass excess property checking
- Assign to a variable first (structural typing)
- Use index signatures or Record types
interface User {name: string;age: number;}// ERROR: 'email' doesn't exist in Userfunction saveUser(user: User) {}saveUser({ name: 'John', age: 30, email: 'john@example.com' });// Object literal may only specify known properties...// FIX: Remove the extra propertysaveUser({ name: 'John', age: 30 });// OR if 'email' should be included, update the interface:interface User {name: string;age: number;email?: string; // Make it optional}Object literal may only specify known properties, and 'name' does not exist in type 'T'. ts(2353)
What this error means
The "Object literal may only specify known properties" error is TypeScript's way of enforcing strict type checking when you create object literals. This is part of TypeScript's excess property checking feature, which helps catch common bugs like typos in property names or accidentally passing extra data. When you pass an object literal directly to a function or assign it to a variable with a specific type, TypeScript performs extra validation beyond normal type compatibility. It checks that every property in the object literal exists in the target type. This prevents subtle bugs where you might think you're passing certain data but actually have a typo in a property name. For example, if you have an interface `User` with properties `name` and `age`, and you try to create `{name: 'John', age: 30, email: 'john@example.com'}` where `User` doesn't have an `email` property, TypeScript will flag this as an error. This is different from assigning an existing object variable, which would be allowed due to structural typing.
Typical symptoms
- Compilation fails with 'Object literal may only specify known properties' error
- IDE shows red underlines on object literals passed to typed functions
- Error occurs when creating inline objects but not when using variables
- Code works if you assign the object to a variable first, then pass the variable
- Error highlights specific extra properties that don't exist in the target type
- Common when passing configuration objects or React props
Common causes
- Passing an object literal with extra properties to a typed parameter
- Typo in property name (e.g., 'colour' instead of 'color')
- Using deprecated property names that were removed from the type
- Passing configuration objects with optional properties not declared in the type
- Mismatch between library versions and type definitions
- Incorrect type inference where TypeScript thinks you're passing to a stricter type
- Using object spread with extra properties in a typed context
How to fix "Object literal may only specify known properties, and 'name' does not exist in type 'T'. ts(2353)"
The simplest fix is to remove properties that don't exist in the target type:
interface User {
name: string;
age: number;
}
// ERROR: 'email' doesn't exist in User
function saveUser(user: User) {}
saveUser({ name: 'John', age: 30, email: 'john@example.com' });
// Object literal may only specify known properties...
// FIX: Remove the extra property
saveUser({ name: 'John', age: 30 });
// OR if 'email' should be included, update the interface:
interface User {
name: string;
age: number;
email?: string; // Make it optional
}Check for typos in property names:
// ERROR: Typo in 'colour' (should be 'color')
interface Config {
color: string;
size: number;
}
const config: Config = { colour: 'red', size: 10 };
// Object literal may only specify known properties...
// FIX: Correct the typo
const config: Config = { color: 'red', size: 10 };If you're sure the extra properties are safe, use a type assertion:
interface User {
name: string;
age: number;
}
// ERROR: Extra 'metadata' property
saveUser({ name: 'John', age: 30, metadata: { id: 1 } });
// FIX: Use type assertion
saveUser({ name: 'John', age: 30, metadata: { id: 1 } } as User);
// OR use the newer 'as' syntax
saveUser({ name: 'John', age: 30, metadata: { id: 1 } } as User);
// WARNING: This suppresses the error but the extra property
// will be lost at runtime since TypeScript only affects type checkingFor React props with spread operators:
interface ButtonProps {
label: string;
onClick: () => void;
}
// ERROR: Extra 'className' property
const Button = ({ label, onClick, className }: ButtonProps & { className?: string }) => {
return <button className={className} onClick={onClick}>{label}</button>;
};
// FIX: Update the interface to include className
interface ButtonProps {
label: string;
onClick: () => void;
className?: string;
}TypeScript's structural typing allows extra properties if you assign to a variable first:
interface User {
name: string;
age: number;
}
// ERROR: Direct object literal
saveUser({ name: 'John', age: 30, email: 'john@example.com' });
// FIX: Assign to variable first
const userData = { name: 'John', age: 30, email: 'john@example.com' };
saveUser(userData); // This works!
// Why this works: TypeScript uses structural typing
// The variable 'userData' has at least the properties of User
// Extra properties don't break the contract
// Common pattern for configuration objects:
interface Config {
apiUrl: string;
timeout: number;
}
function initialize(config: Config) {}
// ERROR: Direct literal with extra debug property
initialize({ apiUrl: '/api', timeout: 5000, debug: true });
// FIX: Use variable
const appConfig = { apiUrl: '/api', timeout: 5000, debug: true };
initialize(appConfig); // WorksThis approach is useful when you need to pass extra data for internal use but the function only requires a subset.
If your type should accept any additional properties, use an index signature:
// BEFORE: Strict interface
interface Config {
apiUrl: string;
timeout: number;
}
// ERROR: Can't pass extra properties
const config: Config = { apiUrl: '/api', timeout: 5000, retries: 3 };
// AFTER: Add index signature for extra properties
interface Config {
apiUrl: string;
timeout: number;
[key: string]: any; // Allows any extra string properties
}
// Now this works:
const config: Config = { apiUrl: '/api', timeout: 5000, retries: 3 };
// More type-safe: Use Record for specific value types
interface Config {
apiUrl: string;
timeout: number;
options: Record<string, string | number | boolean>;
}
const config: Config = {
apiUrl: '/api',
timeout: 5000,
options: { retries: 3, debug: true, mode: 'production' }
};
// For React components with spread props:
interface BaseProps {
children: React.ReactNode;
}
type DivProps = BaseProps & React.HTMLAttributes<HTMLDivElement>;
const Container = (props: DivProps) => {
// Can spread all div attributes including className, style, etc.
return <div {...props}>{props.children}</div>;
};For legacy codebases or specific cases, you can disable excess property checking:
// tsconfig.json
{
"compilerOptions": {
"suppressExcessPropertyErrors": true
}
}WARNING: This disables ALL excess property checking globally. Use only as a last resort.
Better approach: Use a more targeted solution with interface merging or utility types:
// Use Partial for optional configurations
interface RequiredConfig {
apiUrl: string;
timeout: number;
}
type Config = RequiredConfig & Partial<{
retries: number;
debug: boolean;
cache: boolean;
}>;
// Now all are optional extras
const config: Config = {
apiUrl: '/api',
timeout: 5000,
retries: 3, // No error
debug: true // No error
};
// Use Omit to remove strictness from specific functions
interface User {
id: string;
name: string;
age: number;
}
function updateUser(id: string, updates: Partial<Omit<User, 'id'>>) {
// Can accept any subset of User properties except 'id'
}
updateUser('123', { name: 'John', extraField: 'value' }); // Error on extraField
// Make it more permissive:
function updateUser(id: string, updates: Partial<Omit<User, 'id'>> & Record<string, any>) {
// Now accepts extra properties
}TypeScript's utility types can help create more flexible interfaces:
// Use intersection types to combine required and optional properties
interface RequiredFields {
name: string;
age: number;
}
interface OptionalFields {
email?: string;
phone?: string;
address?: string;
}
type User = RequiredFields & OptionalFields & Record<string, any>;
// Now User accepts any extra properties
const user: User = {
name: 'John',
age: 30,
email: 'john@example.com',
customField: 'value' // Allowed due to Record<string, any>
};
// For API responses that may include metadata:
type ApiResponse<T> = {
data: T;
success: boolean;
timestamp: string;
} & Record<string, any>;
interface Product {
id: string;
name: string;
price: number;
}
const response: ApiResponse<Product> = {
data: { id: '1', name: 'Widget', price: 9.99 },
success: true,
timestamp: '2024-01-01',
metadata: { page: 1, total: 100 }, // Extra properties allowed
debug: true // Also allowed
};
// Use generics for maximum flexibility
function createConfig<T extends Record<string, any>>(base: T, extras: Record<string, any>) {
return { ...base, ...extras };
}
const config = createConfig(
{ apiUrl: '/api', timeout: 5000 },
{ retries: 3, debug: true } // No type errors
);Advanced notes
### Understanding Excess Property Checking
TypeScript's excess property checking is a form of "freshness" checking that applies only to object literals. When you create an object literal, TypeScript considers it "fresh" and checks it more strictly than an object that comes from a variable.
Key concepts:
1. Fresh objects: Object literals get strict checking
2. Stale objects: Variables/parameters get structural checking
3. Type compatibility: TypeScript uses structural typing (duck typing), but fresh objects have extra rules
### When Excess Property Checking Applies
The check triggers when:
1. Assigning an object literal to a variable with a type annotation
2. Passing an object literal as an argument to a function
3. Returning an object literal from a function with a return type annotation
4. Using object literals in JSX/TSX props
### Bypassing Strategies
1. Type assertions: as Type or <Type>{...}
2. Intermediate variables: Assign to variable first
3. Index signatures: [key: string]: any
4. Utility types: Partial<T> & Record<string, any>
5. tsconfig option: "suppressExcessPropertyErrors": true (not recommended)
### React/JSX Specifics
In React, excess property checking helps catch prop typos:
interface ButtonProps {
onClick: () => void;
children: React.ReactNode;
}
// ERROR: 'onclick' (lowercase) doesn't exist
<Button onclick={() => {}}>Click me</Button>
// Common React patterns:
// 1. Spread operator for HTML attributes
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
}
// 2. Component props with rest parameters
function Card({ title, children, ...rest }: CardProps & React.HTMLAttributes<HTMLDivElement>) {
return <div {...rest}><h2>{title}</h2>{children}</div>;
}### Performance Considerations
Excess property checking happens at compile time and has no runtime impact. However, using index signatures ([key: string]: any) can reduce type safety. Consider more precise alternatives:
// Instead of:
interface LooseConfig {
[key: string]: any;
}
// Use:
interface TypedConfig {
required: string;
optional?: Record<string, string | number | boolean>;
metadata?: {
[K in 'created' | 'modified' | 'version']?: string;
};
}### Testing and Validation
When testing functions that accept object parameters, consider:
1. Creating test data factories that return typed objects
2. Using satisfies operator for inline objects that should match a type
3. Creating helper types for test data that include extra properties
// Using 'satisfies' for test objects
const testUser = {
name: 'Test',
age: 25,
testId: 123 // Extra property for testing
} satisfies User; // Still type-checks against User
// Test data factory
function createTestUser(overrides?: Partial<User> & Record<string, any>): User & { testId: number } {
return {
name: 'Test',
age: 25,
testId: Date.now(),
...overrides,
};
}Frequently asked questions
- What does "Object literal may only specify known properties, and 'name' does not" mean?
- The "Object literal may only specify known properties" error is TypeScript's way of enforcing strict type checking when you create object literals. This is part of TypeScript's excess property checking feature, which helps catch common bugs like typos in property names or accidentally passing extra data. When you pass an object literal directly to a function or assign it to a variable with a specific type, TypeScript performs extra validation beyond normal type compatibility.
- How do I fix "Object literal may only specify known properties, and 'name' does not"?
- TS2353 fires when an object literal has a property not in the target type. Fix the typo, widen the type, or assert with 'as'.
- What causes "Object literal may only specify known properties, and 'name' does not"?
- Passing an object literal with extra properties to a typed parameter Typo in property name (e.g., 'colour' instead of 'color') Using deprecated property names that were removed from the type
- Is the "Object literal may only specify known properties, and 'name' does not" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚TypeScript Official Documentation
- 📖TypeScript Handbook - Object Types(Official Docs)
- 📖TypeScript TSConfig - suppressExcessPropertyErrors(Official Docs)
- 🐙