typeof is a runtime operator returning string names of primitives ("string", "object"). In TypeScript, typeof used in Type Space queries the exact compile-time shape of any JavaScript variable, object, or function declaration.1. Value Space vs. Type Space#
To use TypeScript effectively, you must mentally separate your code into two distinct worlds:
- Value Space (Runtime): Contains executable JavaScript code—variables, functions, objects, classes, and runtime
typeofexpressions. - Type Space (Compile-Time): Contains TypeScript type definitions—
interface,type,keyof, type annotations, and type-leveltypeofexpressions. All of Type Space is completely erased during compilation.
const appSettings = {
theme: "dark",
maxUploadMb: 50,
features: ["auth", "payments"],
};
// 1. Value Space (Runtime JS typeof check):
if (typeof appSettings.maxUploadMb === "number") {
console.log("Valid upload limit.");
}
// 2. Type Space (Compile-Time TS typeof query):
type AppSettings = typeof appSettings;
/* Inferred Type:
{
theme: string;
maxUploadMb: number;
features: string[];
}
*/2. Reverse-Engineering Types from Runtime Objects#
Instead of creating a complex interface manually and trying to keep it in sync with a default config object, use typeof to derive the type directly from the object value:
// Single Source of Truth Runtime Config Object
export const defaultDbConfig = {
host: "localhost",
port: 5432,
database: "app_db",
pool: {
min: 2,
max: 10,
},
ssl: false,
};
// Derive the TypeScript interface directly from the runtime object:
export type DbConfig = typeof defaultDbConfig;
// Use derived type in factory functions:
function initializePool(config: DbConfig) {
console.log(`Connecting to ${config.host}:${config.port}/${config.database}`);
}
initializePool(defaultDbConfig); // 🟢 WORKED!
3. Extracting Function Signatures#
You can use typeof to capture the complete parameter and return signature of a function declaration:
function calculateOrderTotal(subtotal: number, taxRate: number, discountCode?: string): number {
const discount = discountCode === "PROMO10" ? 10 : 0;
return (subtotal - discount) * (1 + taxRate);
}
// 🟢 Extract the function signature type:
type OrderCalculatorFn = typeof calculateOrderTotal;
// Inferred Type: (subtotal: number, taxRate: number, discountCode?: string) => number
// Apply signature to a mock function:
const mockCalculator: OrderCalculatorFn = (sub, tax, disc) => 100;4. Combining typeof with Utility Types (ReturnType & Parameters)#
By combining typeof with TypeScript’s built-in utility types, you can extract individual components of a function signature:
function buildUserSession(userId: string, role: "admin" | "user") {
return {
sessionId: `sess_${userId}_${Date.now()}`,
user: { id: userId, role },
expiresAt: new Date(Date.now() + 3600000),
};
}
// 1. Extract Return Type from function value:
type UserSession = ReturnType<typeof buildUserSession>;
/* Inferred Type:
{
sessionId: string;
user: { id: string; role: "admin" | "user" };
expiresAt: Date;
}
*/
// 2. Extract Parameter Tuple from function value:
type SessionParams = Parameters<typeof buildUserSession>;
// Inferred Type: [userId: string, role: "admin" | "user"]
5. The Ultimate Combo: keyof typeof#
The keyof typeof pattern is the standard TypeScript design pattern for creating strict string literal unions from runtime dictionary objects or as const config maps.
// 1. Define runtime object dictionary with 'as const'
export const API_ENDPOINTS = {
AUTH_LOGIN: "/api/v1/auth/login",
USER_PROFILE: "/api/v1/user/profile",
PAYMENT_CHECKOUT: "/api/v1/payment/checkout",
} as const;
// 2. Extract key union using 'keyof typeof':
export type ApiEndpointKey = keyof typeof API_ENDPOINTS;
// Inferred Type: "AUTH_LOGIN" | "USER_PROFILE" | "PAYMENT_CHECKOUT"
// 3. Extract value union using 'typeof OBJ[keyof typeof OBJ]':
export type ApiEndpointUrl = typeof API_ENDPOINTS[keyof typeof API_ENDPOINTS];
// Inferred Type: "/api/v1/auth/login" | "/api/v1/user/profile" | "/api/v1/payment/checkout"
// 4. Implement type-safe route fetcher:
function callApi(endpointKey: ApiEndpointKey) {
const url: ApiEndpointUrl = API_ENDPOINTS[endpointKey];
console.log(`FETCH -> ${url}`);
}
callApi("AUTH_LOGIN"); // 🟢 Output: "FETCH -> /api/v1/auth/login"
// ❌ Compiler Error: Argument of type '"INVALID_KEY"' is not assignable to parameter of type 'ApiEndpointKey'.
// callApi("INVALID_KEY");
Summary & Next Steps#
In this episode:
- We separated Value Space (runtime JS expressions) from Type Space (compile-time TS declarations).
- We reverse-engineered object types from runtime variables (
type Config = typeof defaultConfig). - We extracted function signatures,
ReturnType<typeof fn>, andParameters<typeof fn>. - We mastered the
keyof typeofpattern foras constconfiguration dictionaries.
In Episode 29: Introduction to Generics, we will step into TypeScript’s most powerful feature: passing types as variables using Generics (<T>)!

