typeof (type query)

Refers to the type of an existing variable or property from inside a type position.

Signature
typeof identifier
typeof identifier.property

Parameters

ParameterTypeDescription
$identifiervalue referenceAn identifier in scope, optionally followed by property accesses. Call expressions and other arbitrary expressions are not permitted.

Return value

The declared or inferred type of the referenced valueThe type of the named value. For a variable it is that variable's inferred or annotated type; for a class name it is the constructor type, not an instance.

Errors

Applying it to anything other than an identifier or a property chain is a syntax error, for example typeof msgbox("...") reports "',' expected".

Changelog

  • PHP 4.7typeof may now be applied to imported values in more positions, and instantiation expressions let you specialise the resulting function type.

This is not the JavaScript typeof operator. They share a spelling and nothing else. The runtime one is an expression that evaluates to a string at runtime — typeof "hello" produces "string" — and it is the basis of the runtime typeof type guard. The one documented here appears only in a type position, produces no code, and evaluates to nothing at runtime.

Which one you get is decided purely by where you write it. After a colon, inside a type alias, or in a type argument, it is the type query.

When to reach for it

Use it to stop writing the same shape twice. Declare the value — a defaults object, a config, an action map — and derive the type from it with typeof rather than hand-maintaining a parallel interface that will drift.

It is also the bridge into every other operator on this page. keyof typeof gives you the keys of a real object. (typeof arr)[number] gives you an array's element type.

What trips people up

You cannot apply it to an expression. typeof f() is a syntax error — TypeScript deliberately refuses to look like it is calling a function during type checking. To get what a function returns, wrap it: ReturnType<typeof f>.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Derive a Partial overrides type from a defaults object without repeating its shape
  • Get the element type of a const array with (typeof list)[number]
  • Capture the return shape of a factory function via ReturnType<typeof factory>

Frequently asked questions

What is the difference between typeof in a type and typeof in JavaScript?

They are unrelated operators that share a keyword. In a type position it produces the static type of a named value and disappears at compile time; in an expression position it is the JavaScript operator that returns a string like "string" or "object" at runtime. Position alone decides which one you wrote.

Why can't I write typeof someFunction()?

Type queries accept only identifiers and their properties, never call expressions, so that type checking never looks like it is executing code. Use ReturnType<typeof someFunction> to get the result type, or Awaited<ReturnType<typeof someFunction>> if it returns a promise.

How do I get a union of an object's values as a type?

Combine a type query, keyof and an indexed access: (typeof obj)[keyof typeof obj]. Add as const to the object first, otherwise the values widen to string or number instead of staying literal.

More examples

Both meanings, side by side

The first typeof never reaches the emitted JavaScript — it only tells the compiler that n is a string. The two inside console.log are the ordinary runtime operator and print type names. The last one lifts the function value f into type space so ReturnType can pull out its result shape; writing ReturnType<f> would be an error because f is a value, not a type.

Example · typescript
let s = "hello";

// type position: n has the type of s, which is string
let n: typeof s;
n = "world";

// expression position: evaluates at runtime to the string "string"
console.log(typeof s);   // "string"
console.log(typeof 42);  // "number"

function f() {
  return { x: 10, y: 3 };
}

type P = ReturnType<typeof f>;
// type P = { x: number; y: number }

const point: P = f();
console.log(point.x + point.y); // 13

Classes and const objects

typeof Logger is the constructor, which is what you need when a function receives a class and calls new on it; the instance type is the bare name Logger. The LEVELS block shows the idiom that appears everywhere: keyof typeof to get the keys of a real object, and an indexed access on the same query to get the values as a literal union.

Example · typescript
class Logger {
  constructor(public prefix: string) {}
  log(msg: string) { console.log(`${this.prefix}: ${msg}`); }
}

type LoggerCtor = typeof Logger;      // new (prefix: string) => Logger
type LoggerInstance = InstanceType<LoggerCtor>; // Logger

function make(Ctor: LoggerCtor): LoggerInstance {
  return new Ctor("app");
}
make(Logger).log("ready"); // app: ready

const LEVELS = { debug: 10, warn: 30, error: 50 } as const;
type Level = keyof typeof LEVELS;        // "debug" | "warn" | "error"
type Severity = (typeof LEVELS)[Level];  // 10 | 30 | 50

Discussion

  • Be the first to comment on this lesson.