keyof, typeof and indexed access: building types from your values
Derive types from data instead of writing them twice: keyof for property names, typeof in type position, T[K] to read a property's type, and T[number] for array items.
Comes up in: Coding
Learn#
Kavya adds a “team” plan to the pricing array. The checkout breaks, because a hand-written type PlanId = "free" | "pro" lives in another file, and nobody updated it.
When a type repeats data you already have, derive the type from the data. Three operators do it:
const PLANS = [
{ id: "free", price: 0 },
{ id: "pro", price: 499 },
{ id: "team", price: 1999 },
] as const;
type Plan = (typeof PLANS)[number]; // one element of the array
type PlanId = Plan["id"]; // "free" | "pro" | "team"
type PlanKey = keyof Plan; // "id" | "price"
function priceOf(id: PlanId) {
return PLANS.find((p) => p.id === id)?.price;
}
priceOf("pro");
priceOf("enterprise");
const key: PlanKey = "currency";example.ts(15,9): error TS2345: Argument of type '"enterprise"' is not assignable to parameter of type '"free" | "pro" | "team"'.
example.ts(16,7): error TS2322: Type '"currency"' is not assignable to type '"id" | "price"'.In a type, typeof PLANS means “the type of this value”. The keyof operator gives the union of a type’s property names. An indexed access type, T["id"], gives the type of one property.
State
- typeof PLANS = readonly [{id:"free"…}, {id:"pro"…}, {id:"team"…}]
typeof PLANS reads the type of the value: a readonly tuple of three objects.
Read the steps as text
- typeof PLANS reads the type of the value: a readonly tuple of three objects.
- [number] asks: what type do you get with any number index? The union of all three objects.
- Plan["id"] reads the id property's type from each member.
- Add a fourth plan to PLANS, and PlanId updates by itself. There is one source of truth.
Predict#
Predict first
const SIZES = ['sm', 'md']; (no as const). What is (typeof SIZES)[number]?
Without as const, the array’s type is string[], so its element type is string. The literals were widened when the array was created (TS.02.04). That is why the derived-union pattern always starts with as const.
Interview angle#
Say it like this — about 30 seconds
“keyof T gives the union of T’s property names. typeof, used in a type, gets the type of a value, so I can derive types from constants instead of writing them twice. T[K] reads the type of property K, and T[number] gives the element type of an array or tuple. To get a union from an array of strings, I declare it as const and write typeof arr[number]. Then adding a value updates the type automatically.”
Follow-up How do you get a union type from an array of string constants?
as const, then type Item = (typeof ARR)[number].Follow-up How do you type get(obj, key) so the result has the right type?
function get<T, K extends keyof T>(obj: T, key: K): T[K].Follow-up What is keyof { [key: string]: X }?
string | number, because numeric keys are also allowed on a string index signature. (For Record<string, X> it is string.)Practice#
Guided
Type get and pluck with keyof and T[K], and derive Status from STATUSES.
Done when
getis typed<T, K extends keyof T>(obj: T, key: K): T[K].pluckreturns the property’s values in order, typedT[K][].Statusis derived fromSTATUSES, andisStatusis a type guard for exactly those strings.
Remember#
Try to answer each card before you open it. Then add them to your reviews.
What does keyof T give?
A union of T's property names.
What does typeof x mean inside a type?
The type of the value x.
What does T[number] give for an array type?
The type of its elements.
Why does deriving a union from an array need as const?
Without it, the strings widen to string.
Go deeper
Four layers. Stop at the one your interview needs; each ends with a quick check.
The core ideaEvery round
keyof { id: string; price: number } is "id" | "price".Plan["price"] is the price’s type, and Plan["id" | "price"] gives a union of both property types.Check yourself: Write the type of the price property of Plan.
Plan["price"]
How it works underneathSenior rounds
typeof accepts only names and property paths, such as typeof config.theme. For a function’s result, use ReturnType<typeof fn> Source: TypeScript Handbook: Typeof type operator.Check yourself: Can you write typeof someFunction() in a type?
No. typeof in types takes a name or property path, not a call; use ReturnType<typeof fn>.
Edge cases and trapsWhere people slip
T[number] gives the element type of any array; on a tuple it is the union of all positions, and T[0] is the first position’s type Source: TypeScript Handbook: Indexed access types.keyof an array type includes number and every method name, so it is rarely what you want.Check yourself: What is (readonly ['a', 'b'])[0]?
"a" — a tuple index gives that position's type.
In productionStaff-level answers
Keep one constant for routes, feature flags, statuses or event names, and derive every type from it. Mapped types (TS.05.03) and conditional types (TS.05.02) build on these operators to transform whole objects.
Check yourself: Name a place to use the derived-union pattern in a frontend codebase.
Feature flags, routes, status lists, theme tokens or event names.
Finished the five steps? Mark it, and its cards join your reviews.
Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.
Interview questions this answers
- How do you get a union type from an array of string constants?