On this page · sections
Advanced Type Operators
TypeScript provides type operators that compute types from other types — typeof, keyof, indexed access, template literals, and infer. Senior frontend engineers use them for typed routes, event systems, design tokens, and keeping client code in sync with runtime values.
| Operator | Input | Output |
|---|---|---|
typeof | Value | Type of value |
keyof | Object type | Union of keys |
T[K] | Object + key | Property type |
`${A}-${B}` | String unions | Combined string union |
infer | Pattern in conditional | Extracted inner type |
typeof — types from values
Definition
typeof at the type level extracts the type of a value (variable, function, const object):
const config = {
apiUrl: "/api",
retries: 3,
features: { darkMode: true },
} as const;
type Config = typeof config;
// { readonly apiUrl: "/api"; readonly retries: 3; ... }
type ApiUrl = typeof config.apiUrl;
// "/api"Real-world example — infer from factory
function createStore<T extends Record<string, unknown>>(initial: T) {
let state = initial;
return {
getState: () => state,
setState: (patch: Partial<T>) => {
state = { ...state, ...patch };
},
};
}
const store = createStore({ count: 0, user: null as string | null });
type StoreState = ReturnType<typeof store.getState>;
// { count: number; user: string | null }typeof vs runtime typeof
// Runtime — JavaScript operator
typeof "hello"; // "string"
// Type level — TypeScript operator
type S = typeof "hello"; // "hello" (literal type when const)Interview: Pair
typeofwithas constto get narrow literal unions from runtime constants.
keyof — advanced usage
Definition
Beyond simple objects, keyof works on arrays, tuples, and mapped results:
type Colors = { red: string; blue: string };
type ColorKey = keyof Colors; // "red" | "blue"
type NumTuple = [number, string, boolean];
type TupleKey = keyof NumTuple; // "0" | "1" | "2" | "length" | ...keyof with generics
function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const name = pluck(user, "name"); // stringFilter keys with conditional mapped types
type KeysOfType<T, V> = {
[K in keyof T]: T[K] extends V ? K : never;
}[keyof T];
type User = { id: string; name: string; age: number };
type StringKeys = KeysOfType<User, string>; // "id" | "name"Indexed access types
Definition
Look up property types using literal or union keys:
type User = {
id: string;
profile: { bio: string; avatar: string };
};
type Bio = User["profile"]["bio"]; // string
type ProfileSlice = User["id" | "profile"];
// string | { bio: string; avatar: string }Array element access
type Item = { id: string }[];
type Element = Item[number]; // { id: string }
type Head<T extends readonly unknown[]> = T extends readonly [infer H, ...unknown[]]
? H
: never;
type First = Head<[string, number]>; // stringLookup from const arrays
const STATUSES = ["idle", "loading", "error"] as const;
type Status = (typeof STATUSES)[number];
// "idle" | "loading" | "error"Template literal types
Definition
Build string types from patterns, similar to template strings at runtime:
type Greeting = `Hello, ${string}`;
const a: Greeting = "Hello, world"; // ✅
const b: Greeting = "Hi, world"; // ❌Combine literal unions — TypeScript takes the Cartesian product:
type Color = "red" | "blue";
type Size = "sm" | "lg";
type Variant = `${Color}-${Size}`;
// "red-sm" | "red-lg" | "blue-sm" | "blue-lg"Interview: Template literals distribute over unions in each
${}slot.
Typed event names
Real-world example
type Entity = "user" | "order";
type Action = "created" | "updated" | "deleted";
type DomainEvent = `${Entity}:${Action}`;
// "user:created" | ... | "order:deleted"
function emit(event: DomainEvent, payload: unknown) {
analytics.track(event, payload);
}
emit("user:created", { id: "1" }); // ✅
emit("user:invalid", {}); // ❌DOM-style custom events
type WidgetEvent = `widget:${"open" | "close" | "submit"}`;
function onWidgetEvent(name: WidgetEvent, handler: () => void) {
document.addEventListener(name, handler);
}CSS and design tokens
type CSSProperty = "margin" | "padding";
type Side = "Top" | "Right" | "Bottom" | "Left";
type CSSPropertyWithSide = `${CSSProperty}${Side}`;
// "marginTop" | "marginRight" | ... | "paddingLeft"
type StyleKey = `--${string}`;
const token: StyleKey = "--color-primary"; // ✅Token scales
type TokenCategory = "color" | "spacing" | "font";
type TokenScale = "sm" | "md" | "lg";
type DesignToken = `${TokenCategory}-${TokenScale}`;
const spacing: Record<DesignToken, string> = {
"color-sm": "#000",
"color-md": "#333",
"color-lg": "#666",
"spacing-sm": "4px",
"spacing-md": "8px",
"spacing-lg": "16px",
"font-sm": "12px",
"font-md": "14px",
"font-lg": "18px",
};Built-in string transforms
type Upper = Uppercase<"hello">; // "HELLO"
type Lower = Lowercase<"HELLO">; // "hello"
type Cap = Capitalize<"hello">; // "Hello"
type Uncap = Uncapitalize<"Hello">; // "hello"camelCase from snake_case
type CamelCase<S extends string> = S extends `${infer Head}_${infer Tail}`
? `${Head}${Capitalize<CamelCase<Tail>>}`
: S;
type Camel = CamelCase<"user_id">; // "userId"Typed routes
type StaticRoute = "/" | "/about" | "/settings";
type DynamicSegment = `[${string}]`;
type AppRoute = StaticRoute | `/users/${DynamicSegment}` | `/posts/${DynamicSegment}`;
function navigate(path: AppRoute) {
router.push(path);
}
navigate("/users/[id]"); // ✅Production apps often generate route types from a file-based router or a central route map.
as const + template literals
const EVENTS = ["click", "focus", "blur"] as const;
type EventName = (typeof EVENTS)[number];
type HandlerName = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"Bridges runtime constants and compile-time string unions — the pattern behind many React prop typings.
Limitations
Very large union products → slow type checking (avoid huge cartesian expansions)
Runtime strings → won't match unless validated and narrowed
Template types erase at runtime → still need runtime checks for user input
Recursive string parsing → depth limits; prefer code gen for complex pathsSenior Interview Summary
What to say
typeofbridges runtime values and static types.keyofand indexed access derive shapes from existing types. Template literal types compose string unions for events, tokens, and routes.inferextracts pieces from matched patterns.
Operator cheat sheet
typeof value → type of a value
keyof T → union of keys
T[K] → property type at K
`${A}-${B}` → string union product
infer X → capture in conditional matchCommon patterns
typeof + as const → literal unions from constants
keyof typeof obj → keys of runtime object
T[number] → array element type
`${Entity}:${Action}` → domain events
Capitalize + as const → React handler prop namesPractical rule
Finite known sets → template literal unions
User-provided strings → validate at runtime, then narrow
Huge cross products → split types or use branded strings
Derive from source → typeof / keyof before hand-copying