Object Types in TypeScript
An object type describes the shape of a JavaScript object by listing its properties and their expected types. Learn how to write object types, what the compiler checks, and how they catch common bugs.
TypeScript object types describe the shape of a JavaScript object. They list the property names an object must have and what type each property should be. The compiler uses this description to check that you only access properties that exist and that you assign values of the correct type.
In plain JavaScript, accessing a misspelled property returns undefined silently. TypeScript catches that mistake at compile time instead.
Writing an object type
You write an object type between curly braces, listing each property name followed by its type. Separate properties with commas or semicolons -- both work the same way.
let user: { name: string; age: number } = {
name: "Ada",
age: 30,
};This tells the compiler that user must have a name of type string and an age of type number. After this declaration, the compiler enforces those rules everywhere user is used.
Here is a function that uses an inline object type for its parameter:
function printCoord(pt: { x: number; y: number }) {
console.log(`x: ${pt.x}, y: ${pt.y}`);
}
printCoord({ x: 3, y: 7 }); // x: 3, y: 7The annotation says that pt must be an object with x and y properties, both numbers. If you try to access a property that does not exist, the compiler stops you before the code ever runs.
The property type can be any TypeScript type: primitives, arrays, unions, other object types, or even function signatures. Nesting is also supported:
let config: {
title: string;
tags: string[];
metadata: { created: Date; version: number };
} = {
title: "My Project",
tags: ["typescript", "tutorial"],
metadata: { created: new Date(), version: 1 },
};The metadata property is itself an object type with its own created and version fields. You can nest as deeply as your data model requires.
What the compiler checks
When you annotate a variable or parameter with an object type, TypeScript checks three things. First, every property you access must be declared in the type. Second, assigned values must match the declared types. Third, the object must have at least the required properties.
Here is an example of a missing property:
function greet(person: { name: string; age: number }) {
console.log(`Hello, ${person.name}.`);
}
greet({ name: "Ada" });
// Error: Property 'age' is missing in type '{ name: string; }'
// but required in type '{ name: string; age: number; }'.TypeScript tells you exactly what is missing and where. This feedback appears in your editor and during compilation, so the problem never reaches runtime.
Excess property checks
There is one extra rule that applies only to object literals: excess property checking. When you pass an object literal directly to a typed variable or function, TypeScript rejects properties not in the type, even if all required properties are present.
function createUser(data: { name: string; age: number }) {
return data;
}
// Error: 'email' does not exist in type
createUser({ name: "Ada", age: 30, email: "ada@example.com" });This catches typos. If you meant to write name but typed naem, the compiler flags it as an unknown property instead of silently creating a new property with undefined as the real name value.
Excess property checking only fires on object literals. If you assign the object to a variable first, the check is skipped because TypeScript assumes you want the extra properties for some other use:
const input = { name: "Ada", age: 30, email: "ada@example.com" };
createUser(input); // OK -- variable already has the wider typeThe variable input already has a wider inferred type that includes email, so passing it to createUser is allowed. The function only uses name and age, and the extra email does not break anything.
Object types and structural typing
TypeScript uses structural typing: the compiler only cares about the shape of the value, not its name. Two types with the same properties are compatible.
interface Point { x: number; y: number; }
interface Coordinate { x: number; y: number; }
let p: Point = { x: 10, y: 20 };
let c: Coordinate = p; // OKThis works because both types require the same properties. TypeScript does not check the name, only the structure.
Structural typing also means an object can have more properties than the type requires and still be valid. A function that only needs a label property will accept any object that has at least that property:
function printLabel(obj: { label: string }) {
console.log(obj.label);
}
const item = { label: "Milk", price: 2.5, inStock: true };
printLabel(item); // "Milk"The item variable has three properties, but printLabel only cares about label. This is safe because the function only uses that one property.
When to name your object types
Inline object types are fine for a single function parameter. But when the same shape appears in multiple places, give it a name. Naming the type makes the code easier to read and change. If you add a new required property later, you update one interface instead of three inline annotations.
For more on naming types, see interfaces in TypeScript explained and type aliases in TypeScript explained.
Common mistakes
Expecting object types to exist at runtime. They do not. Object types are erased during compilation. If you need to check the shape of data at runtime -- for example, validating an API response -- you need runtime validation. See runtime validation in TypeScript.
Forgetting that extra properties are usually allowed. Assigning an object with extra properties to a typed variable is fine, as long as it is not an object literal. The excess property check is a special case for literals.
Confusing the type syntax with the value syntax. The curly braces in a type annotation describe a shape. The curly braces in a value create an object. They look similar but serve different purposes. Type annotations only appear after a colon in a variable declaration, parameter, or return type.
Rune AI
Key Insights
- An object type lists property names and their expected types between curly braces.
- TypeScript checks that accessed properties exist and that assigned values match the declared types.
- Object types exist only at compile time and are erased from the compiled JavaScript.
- Excess property checks catch typos in object literals assigned directly to a typed position.
- Name reusable shapes with an interface or type alias instead of repeating the inline type.
Frequently Asked Questions
Do object types exist at runtime?
Can I use commas instead of semicolons in object types?
What happens if I access a property not in the object type?
Conclusion
Object types describe the shape of JavaScript objects so the compiler can verify property access, function arguments, and return values. They are the most common type you will write in TypeScript. Write them inline for quick annotations, or name them with an interface or type alias when the same shape is used in multiple places.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.