Bisexual Pride

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.