The satisfies
keyword is a type-checking operator introduced in TypeScript 4.9. It allows you to validate that a value matches a specific type while still preserving the literal and detailed structure of the value itself.
This operator is useful when you want to make sure an object fits a particular shape but don’t want TypeScript to widen the type or throw away extra information. In other words, it helps you keep strong type safety without losing useful data.
The main benefit of using the satisfies
keyword is that it gives you both safety and precision.
When you use as
, TypeScript may let things slide or widen types in ways you don’t intend. With satisfies
, TypeScript checks that your value conforms to the target type at compile time, and it will give an error if it doesn’t.
At the same time, satisfies
doesn’t throw away the extra fields or narrow literal types — it keeps them available for IntelliSense and other autocomplete tooling.
type User = {
id: number;
role: 'admin' | 'user';
};
const admin = {
id: 1,
role: 'admin',
extra: 'metadata' // extra field not part of User
} satisfies User; // Valid: has all required fields of User
// The object passes type checking, but `admin.extra` is still accessible.
In this example, TypeScript confirms that the object has all the required fields from the User
type. At the same time, it preserves the extra
property and the exact string value 'admin'
for later use.
Developers often use the as
keyword to tell TypeScript to treat a value as a certain type. However, as
simply forces the type and does not validate the structure.
const user1 = {
id: 1
} as User; // No error! But 'role' is missing — this could lead to bugs
TypeScript trusts you with as
and skips strict validation. This can lead to runtime issues if something is missing.
With satisfies
, TypeScript ensures the object matches the type exactly.
const user2 = {
id: 1
} satisfies User; // Compile-time error: Property 'role' is missing
This is a safer approach because it ensures your object truly matches the type. That’s why many developers are now preferring satisfies
over as
.
The extends
keyword is used when you’re working with types, not values. It’s mainly used to build on top of other types, for example, to create a more specific version of a base type.
Here’s how extends
works in type declarations:
type User = {
id: number;
role: 'admin' | 'user';
};
type Admin = User & {
accessLevel: number;
};
// or using extends syntax for generics
type ApiResponse<T> = {
status: number;
data: T;
};
type UserResponse = ApiResponse<User>;
In the first example, Admin
extends User
by adding a new field accessLevel
. This lets you reuse and build on existing types.
But you can’t use extends
directly on values — that’s where satisfies
comes in.
const superAdmin = {
id: 2,
role: 'admin',
accessLevel: 10
} satisfies Admin; // Valid: includes all required fields from Admin
If you omit a required field, TypeScript will show a compile-time error:
const invalidAdmin = {
id: 2,
role: 'admin'
} satisfies Admin; // Error: Property 'accessLevel' is missing
So in short:
- Use
extends
when you’re defining or combining types. - Use
satisfies
when you’re validating a value against a type at compile time.
They serve different purposes:extends
creates relationships between types,satisfies
checks relationships between values and types.
You can use satisfies
with Record
to validate that an object fits a key-value structure.
const config = {
theme: 'dark',
layout: 'grid'
} satisfies Record<string, string>; // All values are strings
If one of the values is the wrong type, TypeScript will catch it:
const invalidConfig = {
theme: 'dark',
debug: true
} satisfies Record<string, string>; // Error: boolean is not assignable to string
Here’s an example where satisfies
is used with a custom type, but the object includes extra properties.
type Point = {
x: number;
y: number;
};
const origin = {
x: 0,
y: 0,
label: 'origin point' // not part of Point
} satisfies Point; // Valid: has all required fields from Point
You get type safety on required fields, and the extra fields are preserved in the variable’s full type.
satisfies
can be combined with generics such as Record<string, unknown>
to enforce shape on dynamic objects.
const data = {
id: 123,
isActive: true
} satisfies Record<string, unknown>; // Valid: both values fit 'unknown'
If any value doesn’t match the constraints of the type, TypeScript will warn you.
Use satisfies
when:
- You want to validate that a value matches a type at compile time
- You want to keep extra fields for extended use or flexibility
- You’re working with configuration, settings, themes, or constant maps
- You want to preserve literal types for better IntelliSense
- You care about stronger type checking than what
as
gives you
The satisfies
keyword in TypeScript is a valuable tool for enforcing type correctness without sacrificing extra information or developer experience. Compared to as
, it provides safer compile-time validation. And unlike extends
, it works directly with values.
Whether you’re validating configuration objects, working with Record
types, or building flexible systems with strong type checks, satisfies
gives you a modern, precise way to write reliable TypeScript code.
If you enjoyed this article, I’d truly appreciate it if you could share it—it really motivates me to keep creating more helpful content!
If you’re interested in exploring more, check out these articles.
- 4 Ways To Handle Asynchronous JavaScript
- Overloading vs Overriding in TypeScript
- How to Use Discriminated Unions in TypeScript?
Thanks for sticking with me until the end—I hope you found this article valuable and enjoyable!
Want more dev insights like this? Subscribe to get practical tips, tutorials, and tech deep dives delivered to your inbox. No spam, unsubscribe anytime.