Typorithm · medium

10. keyof, typeof and indexed access

typescriptstable-typescriptinterviewindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

10. keyof, typeof and indexed access

0%

Concept and contract

Connect known property names to the values they select.

keyof T produces the keys available on a type. An indexed access T[K] selects the corresponding property value type. Combined with a constrained key parameter, these operators let a helper preserve the relationship between a chosen field and its precise result.

The type-position typeof operator derives a type from an existing value declaration. It is distinct from the runtime typeof expression used in guards. Derive vocabulary from one canonical configuration when that reduces drift, but do not make private implementation details the accidental public API.

Mechanism and worked example

The example constrains K to keyof T and returns T[K].

The example constrains K to keyof T and returns T[K]. Selecting title yields string, while selecting count yields number. A return type of T[keyof T] would lose the chosen-key relationship and produce a broader union of every property value.

If T has a string index signature, keyof can include number as well as string because JavaScript coerces numeric property keys. A finite object type has a more specific key union. Inspect the actual object model before assuming every keyof result is a list of string literals.

Complete worked example

typescript

function get<T, K extends keyof T>(object: T, key: K): T[K] { return object[key]; }
const role = { title: "QA", count: 2 };
const count: number = get(role, "count");
Reasoning
K connects the literal key argument to its selected value type T[K].

Counterexamples and common mistakes

The rejected property name does not belong to the object.

The rejected property name does not belong to the object. A string originating from a URL is wider than keyof this record and cannot safely select a field without validation. An assertion may suppress the error while still producing undefined at runtime.

Avoid pairing an independently chosen key union with an independently chosen value union for writes. That permits mismatched combinations. Preserve correlation through K and T[K], or use a discriminated union when the key and payload travel together as stored data.

Rejected counterexample: expected compiler diagnostic

typescript

function get<T, K extends keyof T>(object: T, key: K): T[K] { return object[key]; }
// @ts-expect-error This field is absent from the known shape.
get({ title: "QA" }, "salary");
Reasoning
A runtime string cannot be treated as a known key without evidence.

Independent practice

Implement copyField that receives an object and a valid key, returning a new object with the selected key and value as a tuple.

Implement copyField that receives an object and a valid key, returning a new object with the selected key and value as a tuple. Ensure the tuple preserves both K and T[K]. Do not mutate the source.

Test title and count selections and reject an unknown field. Include a type assertion test through an annotated receiving variable, such as ["count", number], to confirm the relationship remains precise rather than merely checking the runtime spelling.

Step 1: Constrain K to keyof T. Step 2: Return a tuple containing the key and selected value.

Practice starter: solve before reading the solution

typescript

function copyField<T, K extends keyof T>(object: T, key: K): [K, T[K]] { throw new Error("TODO"); }
Reasoning
Preserve the key and selected value in two required tuple positions.
  • Hint 1: The return tuple is [K, T[K]].
  • Hint 2: An arbitrary array would lose positional information.

Solution, tests and trade-offs

The solution returns a tuple with an explicit [K, T[K]] annotation.

The solution returns a tuple with an explicit [K, T[K]] annotation. This prevents array inference from widening the two positions into an arbitrary sequence. The generic constraint ensures indexing is legal; the tuple contract preserves positional meaning for the consumer.

A runtime check confirms the selected field and source nonmutation. A compile-time receiving assignment confirms precision. Remember that a structurally typed object may carry additional runtime fields, so Object.keys cannot automatically be asserted as exactly keyof T in every generic function.

Practice solution and acceptance checks

typescript

function copyField<T, K extends keyof T>(object: T, key: K): [K, T[K]] {
  return [key, object[key]];
}
const selected: ["count", number] = copyField({ title: "QA", count: 2 }, "count");

// Acceptance checks
if(selected[0]!=="count"||selected[1]!==2||copyField({title:"QA"},"title")[1]!=="QA")throw new Error("tuple");
Reasoning
The explicit tuple return prevents widening to a loose array of unions.

Interview reasoning and next step

In interviews, compare keyof typeof config with typeof config[key] in the appropriate type syntax.

In interviews, compare keyof typeof config with typeof config[key] in the appropriate type syntax. Explain why keys, selected values and runtime enumeration are related but not interchangeable. Demonstrate the difference between T[K] and T[keyof T].

These relationships underpin mapped types and typed event APIs in the advanced course. First, finish the foundations work on unknown errors and modules so those APIs remain honest across real runtime boundaries.

Optional stretch — after the core task works: Add a typed immutable update and test mismatched values.

Connect known property names to the values they select.