What is typeof in TypeScript?
In TypeScript, the `typeof` keyword serves a dual purpose: it acts as the familiar JavaScript runtime operator to inspect the type of a value at runtime, and it also functions as a powerful type operator at compile-time to infer and extract the type of a variable or property. This dual nature allows TypeScript to build robust type systems based on existing values.
JavaScript's Runtime `typeof` Operator
At its core, typeof is a JavaScript operator that returns a string indicating the type of its unevaluated operand. This operation occurs at runtime, meaning when your code is actually executing. It's useful for conditional logic based on the actual type of a value during execution.
let myString = "hello";
let myNumber = 123;
let myObject = { a: 1 };
let myFunction = () => {};
console.log(typeof myString); // "string"
console.log(typeof myNumber); // "number"
console.log(typeof myObject); // "object"
console.log(typeof myFunction); // "function"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (a historical quirk of JavaScript)
TypeScript's Compile-Time `typeof` Type Operator
Beyond its runtime role, TypeScript extends typeof as a type operator that can be used in type contexts. When used in a type annotation or definition, typeof allows you to extract the type of a variable, property, or even an imported module, at compile-time. This is incredibly useful for ensuring type safety when working with existing values and avoiding redundant type definitions.
Inferring Types from Variables
You can use typeof to get the type of a variable and then assign that type to another variable, ensuring they are compatible.
const greeting = "Hello, TypeScript!";
type GreetingType = typeof greeting; // GreetingType is now 'string'
let anotherGreeting: GreetingType; // 'anotherGreeting' is type 'string'
anotherGreeting = "World"; // OK
// anotherGreeting = 123; // Error: Type 'number' is not assignable to type 'string'.
Inferring Types from Functions (Return Types)
When applied to a function, typeof extracts the function's type signature, including its parameters and return type. To get just the return type of a function, you often combine typeof with the ReturnType<T> utility type.
function createPoint(x: number, y: number) {
return { x, y };
}
type PointCreator = typeof createPoint; // PointCreator is type '(x: number, y: number) => { x: number; y: number; }'
type Point = ReturnType<typeof createPoint>; // Point is type '{ x: number; y: number; }'
const myPoint: Point = { x: 10, y: 20 }; // OK
// const invalidPoint: Point = { x: 10, y: '20' }; // Error
Key Differences and Use Cases
- Runtime vs. Compile-Time: The JavaScript
typeofoperates at runtime and yields a string value. TypeScript'stypeofoperates at compile-time and yields a type. - Type Inference: TypeScript's
typeofis crucial for advanced type inference, allowing types to be derived from existing JavaScript values or expressions without manually declaring them. - Creating New Types: It enables the creation of new types based on the shape of existing variables, objects, or even entire modules, promoting type reuse and reducing duplication.
- Working with Modules/Imports: You can use
typeofto get the type of an imported module, which is particularly useful for namespaces or when you want to re-export types from another module.
Example Scenario: Configuration Object
Imagine you have a default configuration object. Instead of defining an interface manually for it, you can use typeof to automatically derive its type, ensuring consistency.
const defaultConfig = {
port: 3000,
host: "localhost",
debugMode: false,
timeout: 5000
};
type AppConfig = typeof defaultConfig;
function initializeApp(config: AppConfig) {
console.log(`Starting app on ${config.host}:${config.port}`);
if (config.debugMode) {
console.log('Debug mode is ON');
}
}
const customConfig: AppConfig = {
port: 8080,
host: "192.168.1.1",
debugMode: true,
timeout: 10000
};
initializeApp(customConfig);
// initializeApp({ port: '80', host: 'test' }); // Error: Type 'string' is not assignable to type 'number' for 'port'.