TypeScript Record Type: How to Build Dictionary Types with Mapped Types
The TypeScript Record type is a built-in generic utility that constructs an object type where every key is drawn from a union type K and every value is strictly typed as T, effectively creating a homogenous dictionary structure.
The TypeScript Record type provides a concise, declarative way to define object structures where properties share uniform value types. According to the microsoft/TypeScript source code, this utility is defined in the core library files and serves as a fundamental building block for type-safe lookup tables and mapped objects. Understanding how Record works under the hood helps developers leverage structural typing effectively while maintaining strict compile-time checks.
What Is the TypeScript Record Type?
Record<K, T> creates an object type where each key comes from the union type K and each value must conform to type T. The type parameter K must extend keyof any (meaning string, number, or symbol), while T can be any valid TypeScript type.
Because Record is implemented as a mapped type, it behaves like any other object type in the type system. It participates in excess-property checking, works with keyof and lookup types, and follows structural assignability rules. This makes it especially useful for defining lookup tables, configuration dictionaries, and cache objects where consistency across all entries is required.
How Record Is Defined in the TypeScript Source Code
In the microsoft/TypeScript repository, the Record type is declared in src/lib/es5.d.ts at line 1595. The implementation uses a mapped type pattern:
type Record<K extends keyof any, T> = {
[P in K]: T;
}
This definition makes Record available globally without requiring any imports. The TypeScript compiler handles Record through standard mapped type mechanics in src/compiler/checker.ts, ensuring it follows the same structural compatibility rules as manually defined object types.
Practical TypeScript Record Type Examples
String-to-Number Dictionary
Create a simple lookup table mapping string keys to numeric values:
type AgeMap = Record<string, number>;
const ages: AgeMap = {
alice: 30,
bob: 27,
// carol: "thirty" // Error: Type 'string' is not assignable to type 'number'
};
Enum-Based Feature Flags
Use Record with enum keys to build type-safe configuration objects:
enum Feature {
Search = "search",
Share = "share",
Export = "export",
}
type FeatureFlags = Record<Feature, boolean>;
const flags: FeatureFlags = {
[Feature.Search]: true,
[Feature.Share]: false,
[Feature.Export]: true,
};
Union Keys with Complex Values
Map a union of role strings to arrays of user objects:
type User = { id: number; name: string };
type UserRoles = "admin" | "editor" | "viewer";
type RoleAssignments = Record<UserRoles, User[]>;
const assignments: RoleAssignments = {
admin: [{ id: 1, name: "Alice" }],
editor: [{ id: 2, name: "Bob" }, { id: 3, name: "Carol" }],
viewer: [], // Empty arrays satisfy the User[] type
};
Generic Record Factory Function
Build a helper function that constructs a Record from runtime keys:
function fromKeys<K extends keyof any, T>(
keys: readonly K[],
value: T
): Record<K, T> {
return keys.reduce((acc, key) => {
acc[key] = value;
return acc;
}, {} as Record<K, T>);
}
const defaults = fromKeys(["host", "port"] as const, "");
// Type: Record<"host" | "port", string>
Summary
- The TypeScript
Record<K, T>utility creates object types with keys from unionKand uniform values of typeT, defined astype Record<K extends keyof any, T> = { [P in K]: T }. - Defined in
src/lib/es5.d.tsas a mapped type,Recordrequires no imports and works globally across all TypeScript projects. - The type parameter
Kmust extendkeyof any(acceptingstring,number, orsymbol), whileTcan be any type. Recordparticipates in excess-property checking and structural assignability like regular object types.- Common use cases include enum-to-value mappings, dictionary types, and generic factory functions that build consistent object structures.
Frequently Asked Questions
What is the difference between Record and a regular index signature in TypeScript?
While functionally similar to { [key: string]: T }, the Record utility provides a cleaner syntax that explicitly couples specific key unions to value types. The main distinction is that Record enforces that all values share exactly the same type T, whereas index signatures or interface definitions might allow more flexibility in value types across different keys.
Can I use Record with optional properties?
No, the standard Record type does not support optional properties—all keys in union K must be present with a value of type T. If you need optional keys, use a custom mapped type with the ? modifier: { [P in K]?: T } instead of Record<K, T>.
Where is the Record type defined in the TypeScript source code?
The Record type is declared in src/lib/es5.d.ts at line 1595 within the microsoft/TypeScript repository. Additional type-checking logic that handles Record in structural compatibility checks resides in src/compiler/checker.ts, while the public API surface exposes it through src/services/typescriptServices.ts.
Can Record keys be numbers or symbols?
Yes, because the constraint K extends keyof any accepts string, number, or symbol. You can create Record<number, T> for array-like objects or Record<symbol, T> for private property dictionaries, though string keys are the most common implementation in application code.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s https://instagit.com/install.md