JavaScript has a typeof
operator that you can use in an expression context to get a string that indicates the type of a value. This is just a string that represents one of JavaScript’s basic data types, such as "number"
or "boolean"
. TypeScript extends the typeof
operator so that you can use it in a type context to get the type of a variable. This is an actual type that can be used in TypeScript’s type system.
Consider the following code. The user
constant is assigned to an object that represents a user, taken from JSONPlaceholder:
const user = {
id: 1,
name: "Leanne Graham",
username: "Bret",
email: "Sincere@april.biz",
address: {
street: "Kulas Light",
suite: "Apt. 556",
city: "Gwenborough",
zipcode: "92998-3874",
geo: {
lat: "-37.3159",
lng: "81.1496",
},
},
phone: "1-770-736-8031 x56442",
website: "hildegard.org",
company: {
name: "Romaguera-Crona",
catchPhrase: "Multi-layered client-server neural-net",
bs: "harness real-time e-markets",
},
};
In JavaScript and TypeScript, if you use the typeof
operator on this value in an expression context, you will get the string "object"
. This is a string that indicates the basic data type of the value:
console.log(typeof user); // "object"
Imagine you’re writing a function that accepts an object with this shape. You want to create a type for it so that you can get the benefits of TypeScript, including type safety and intelligent code completion. You could painstakingly craft the type by hand:
type User = {
id: number;
name: string;
username: string;
email: string;
address: {
street: string;
suite: string;
city: string;
zipcode: string;
geo: {
lat: string;
lng: string;
};
};
phone: string;
website: string;
company: {
name: string;
catchPhrase: string;
bs: string;
};
};
But this is a lot of typing, especially if you mostly want the type for intelligent code completion! Instead, you can use the typeof
operator in a type context to quickly extract the shape of the object that the user
constant is assigned to:
type User = typeof user;
The result is exactly the same as if you had written the type by hand. You can use it to annotate the type of the user
parameter as normal:
// Expects an object with the shape of the `User` type.
function foo(user: User) {}
If you don’t think you’ll reuse the type, you can even inline the typeof
operator:
// Expects an object with the same shape as the object that the `user` constant
// is assigned to.
function foo(usr: typeof user) {}
The only caveat when inlining the typeof
operator is that the function parameter needs to have a different name from the variable whose type you’re extracting, e.g. usr
in the preceding example. This is because, like JavaScript, TypeScript has no way of knowing that you’re referring to a variable with the same name. How is it supposed to know which one you mean?
// "user" is referenced directly or indirectly in its own type annotation.
function foo(user: typeof user) {}
I made a demo in the TypeScript Playground. For more on this topic, check out the typeof
operator in the TypeScript documentation.