Mastering TypeScript Dictionaries: Index Signatures and Record Types
James Reed
Infrastructure Engineer · Leapcell

Key Takeaways
- TypeScript dictionaries are defined using index signatures or the
Record<K, V>
utility type. - Using specific key types with
Record
enhances type safety and IDE support. - Iteration and immutability are important considerations when working with dictionaries.
TypeScript, being a superset of JavaScript, brings powerful type-checking features to JavaScript development. One commonly used data structure is the dictionary, also referred to as a map or object with dynamic keys. This article explores how to define and use dictionaries in TypeScript, including best practices and type-safe patterns.
What Is a Dictionary in TypeScript?
In TypeScript, a dictionary is typically an object used to store key-value pairs, where the keys are usually strings (or sometimes numbers), and the values can be of any type.
For example:
const scores: { [key: string]: number } = { Alice: 95, Bob: 82, Charlie: 78 };
In this case, scores
is a dictionary where the keys are student names (strings), and the values are their numeric scores.
Defining a Dictionary Type
You can define a reusable dictionary type in multiple ways:
1. Using an Index Signature
type StringToNumberMap = { [key: string]: number; }; const ages: StringToNumberMap = { John: 30, Jane: 25 };
This approach is flexible but does not restrict the possible keys, which may allow typos.
2. Using a Record
Utility Type
TypeScript provides a built-in Record<K, V>
utility type:
const userRoles: Record<string, string> = { admin: 'full-access', guest: 'read-only' };
If the keys are known and fixed, it's better to use specific string literals:
type UserRole = 'admin' | 'guest'; const userPermissions: Record<UserRole, string> = { admin: 'all', guest: 'limited' };
This provides better type safety and IDE autocomplete support.
Optional and Readonly Dictionary Values
You can mark values as optional or readonly:
type UserSettings = { [key: string]: string | undefined; }; const settings: UserSettings = { theme: 'dark', language: undefined };
Or using Record
:
type FeatureFlags = Record<string, boolean | undefined>;
For read-only dictionaries:
const config: Readonly<Record<string, string>> = { version: '1.0.0', env: 'production' };
Iterating Over a Dictionary
You can iterate over the keys of a dictionary like this:
for (const key in scores) { if (scores.hasOwnProperty(key)) { console.log(`${key}: ${scores[key]}`); } }
Or using Object.entries()
for better control:
Object.entries(scores).forEach(([name, score]) => { console.log(`${name}: ${score}`); });
Common Use Cases
- Caching data by ID
- Counting word frequency
- Configuration options
- Mapping between enums and strings
Conclusion
Dictionaries in TypeScript are a versatile and essential data structure. By using index signatures or the Record
utility type, you can build flexible and type-safe dictionaries that integrate well with TypeScript’s static typing system. Understanding the nuances of dictionary types helps you write more robust and maintainable code.
FAQs
Index signatures allow dynamic keys, while Record
provides stricter typing with predefined keys.
Wrap the dictionary type with Readonly<Record<K, V>>
to prevent value modification.
Yes, you can use string | undefined
for values or define them as optional using ?
.
We are Leapcell, your top choice for hosting Node.js projects.
Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:
Multi-Language Support
- Develop with Node.js, Python, Go, or Rust.
Deploy unlimited projects for free
- pay only for usage — no requests, no charges.
Unbeatable Cost Efficiency
- Pay-as-you-go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real-time metrics and logging for actionable insights.
Effortless Scalability and High Performance
- Auto-scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the Documentation!
Follow us on X: @LeapcellHQ