Typeof Type Operator in TypeScript

The typeof type operator captures the TypeScript type of a runtime value. Learn how to use it with ReturnType, keyof, and other type operators for safer type derivations.

5 min read

The TypeScript typeof type operator captures the type of a runtime value and lets you use that type in type annotations. It bridges the gap between values and types, so you do not have to manually rewrite types that already exist in your code.

JavaScript already has a typeof operator that runs at runtime and returns a string:

typescripttypescript
console.log(typeof "hello");

This logs "string" at runtime. TypeScript adds a second use of the same keyword in type contexts. In a type position, typeof extracts the TypeScript type of a variable:

typescripttypescript
let message = "hello";
let copy: typeof message;

The variable copy gets the type string because typeof message evaluates to the type of message. TypeScript infers it without you writing string explicitly.

For primitive values this is not very exciting. The operator becomes powerful when combined with other type operators and complex values.

Using typeof with Functions and ReturnType

One of the most common patterns is capturing a function's return type with ReturnType. You cannot pass a function name directly to ReturnType because it expects a type, not a value:

typescripttypescript
function getUser() {
  return { id: 1, name: "Ada" };
}
 
type User = ReturnType<typeof getUser>;

typeof getUser converts the function value into its type, and ReturnType extracts the return type. The resulting User type is { id: number; name: string }. If you change what getUser returns, the User type updates automatically.

This pattern is common when you have a function that constructs objects and you want a type alias that stays in sync without manual maintenance.

Capturing Array Element Types

For arrays, combine typeof with number indexing to get the element type:

typescripttypescript
const colors = ["red", "green", "blue"] as const;
 
type Color = typeof colors[number];

The as const assertion preserves the literal types. Without it, TypeScript would infer the array as string[] and the element type would just be string. With as const, typeof colors[number] produces "red" | "green" | "blue".

This lets you derive a union type from a runtime array. Change the array and the type updates automatically. For more on literal inference, see use as const in TypeScript.

Using typeof with Object Values

For configuration objects or module-level constants, typeof avoids duplicating type definitions:

typescripttypescript
const config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  retries: 3,
};
 
type AppConfig = typeof config;

AppConfig becomes { apiUrl: string; timeout: number; retries: number }. If you add a property to config or change a value's type, AppConfig stays in sync. You do not need to maintain a separate interface.

Limitations

TypeScript only allows typeof on identifiers and their properties in type positions. You cannot write typeof on a function call or a complex expression:

typescripttypescript
function createUser() {
  return { name: "Ada" };
}
 
type Bad = typeof createUser();

TypeScript's type-position grammar only accepts an identifier after typeof, so the parentheses never parse. This produces a syntax error, not a semantic one:

texttext
';' expected.

The fix is to use typeof on the function name alone and then use ReturnType to get what it returns: type Good = ReturnType<typeof createUser>;.

Typeof vs Keyof: Different Operators for Different Jobs

These two operators solve different problems. Keyof extracts the property names of a type as a union, while typeof captures the type of a runtime value.

They are often used together:

typescripttypescript
const user = { id: 1, name: "Ada", email: "ada@example.com" };
 
type UserKeys = keyof typeof user;

First, typeof user captures the object type. Then, keyof extracts its property names. The result is "id" | "name" | "email".

OperatorInputOutput
typeofA runtime value (identifier)The TypeScript type of that value
keyofA typeA union of that type's property names

For more on keyof, see keyof operator in TypeScript.

Common Mistakes

Confusing runtime typeof with type-level typeof. JavaScript typeof returns a string at runtime. TypeScript typeof in type position produces a TypeScript type at compile time. They look the same but are completely different operations.

Using typeof on a function call. TypeScript does not run your code. You cannot write typeof getUser() to get the return type. Use ReturnType with typeof on the function name instead.

Forgetting as const when deriving literal unions. Without as const, an array of strings gets the type string[], and typeof colors[number] is just string. Add as const to preserve the literal values as types.

Typeof and indexed access types are often used together to derive element types from arrays or property types from objects without writing manual type definitions. For more on this pattern, see indexed access types in TypeScript.

Rune AI

Rune AI

Key Insights

  • The typeof type operator captures the TypeScript type of a runtime value at compile time.
  • It is different from JavaScript typeof, which returns a string at runtime.
  • Combine typeof with ReturnType to capture a function's return type.
  • Combine typeof with number indexing on arrays to get the element type.
  • typeof only works on identifiers and their properties in type context.
RunePowered by Rune AI

Frequently Asked Questions

Is typeof in TypeScript the same as typeof in JavaScript?

No. JavaScript typeof runs at runtime and returns a string like 'string' or 'number'. TypeScript's typeof type operator runs at compile time and produces a TypeScript type. They share the same keyword but operate in completely different contexts.

Can I use typeof on a function call result?

No. TypeScript intentionally limits typeof to identifiers and their properties. You cannot write typeof someFunction() because TypeScript does not evaluate runtime expressions in type positions.

When should I use typeof instead of writing the type manually?

Use typeof when the type is already defined by a runtime value and you want to stay in sync. This is common with module-level constants, configuration objects, and function return types where rewriting the type would create a maintenance burden.

Conclusion

The typeof type operator bridges runtime values and compile-time types. Instead of manually writing a type that mirrors a value, you let TypeScript derive it. This keeps types accurate as values change, especially with const arrays, configuration objects, and function return types. Use it with ReturnType to capture what a function returns, or with indexed access types to drill into specific properties.