These three operators are the vocabulary for deriving types from other types and from real runtime values.
Three operators let you compute types instead of writing them out.
`typeof` in a type position gives the type of a variable or property: type Config = typeof defaultConfig. It's the bridge from values to types — write the object once and derive its type. It only accepts identifiers and property accesses, not arbitrary expressions (typeof f() is invalid; use ReturnType<typeof f>).
`keyof T` is the union of T's property names as literal types: keyof { a: 1; b: 2 } is "a" | "b". Two surprises:
- For a type with a string index signature,
keyofisstring | number, because JavaScript converts numeric keys to strings. keyofof a union only gives keys present in every member.
Indexed access types T[K] look up the type of a property: User["email"] is string. K can be a union (User["id" | "name"] gives the union of those property types) and must be a valid key, otherwise it's an error. Two common idioms:
T[keyof T]— the union of all property value types.T[number]— the element type of an array or tuple type, e.g.(typeof roles)[number].
Combined they let a single runtime constant drive all its related types:
const roles = ["admin", "editor", "viewer"] as const;
type Role = (typeof roles)[number]; // "admin" | "editor" | "viewer"Note the parentheses — typeof roles[number] parses the same way, but writing them makes intent clear. Indexed access works on types, not values: User["email"] is valid in a type, while const k = "email"; User[k] is not — use User[typeof k].
These operators are the inputs to mapped and conditional types, coming next.
Example
const defaultConfig = {
host: "localhost",
port: 8080,
tls: { enabled: false, cert: "" },
};
type Config = typeof defaultConfig; // derived from the value
type ConfigKey = keyof Config; // "host" | "port" | "tls"
type Tls = Config["tls"]; // { enabled: boolean; cert: string }
type ConfigValue = Config[keyof Config]; // string | number | { ... }
const roles = ["admin", "editor", "viewer"] as const;
type Role = (typeof roles)[number]; // "admin" | "editor" | "viewer"
function get<K extends ConfigKey>(key: K): Config[K] {
return defaultConfig[key];
}
const port = get("port"); // number
const tls: Tls = get("tls");
const role: Role = "editor";
type Dict = { [k: string]: boolean };
type DictKey = keyof Dict; // string | number
const v: ConfigValue = 1;
const dk: DictKey = 0;
console.log(port, tls.enabled, role, roles.includes(role), v, dk);Remember
typeof valueturns a runtime value into a typekeyof T= union of property names;T[K]= property typeT[number]gets an array/tuple's element type- Derive types from one constant instead of duplicating them
Watch out for
- Writing
typeof someFunction()— typeof only takes names; useReturnType<typeof someFunction>.