阿里云主机折上折
  • 微信号
Current Site:Index > The `typeof` type operator

The `typeof` type operator

Author:Chuan Chen 阅读数:61508人阅读 分类: TypeScript

Basic Concept of the typeof Type Operator

typeof is an important type operator in TypeScript that can be used in type contexts to obtain the type of a variable or property. Although it shares the same syntax as the typeof operator in JavaScript, its functionality is entirely different. When used in a type position, it returns a type value representing the given variable's type.

let str = "hello";
type StrType = typeof str;  // string

const num = 42;
type NumType = typeof num;  // 42 (literal type)

typeof with Variable Declarations

When applied to variables, typeof captures the declared type of the variable. For variables declared with let or var, typeof yields the variable's type annotation (or the inferred type if no explicit annotation exists). For const-declared primitive variables, typeof yields a literal type.

let x = 10;         // x's type is number
type X = typeof x;  // number

const y = 10;       // y's type is 10
type Y = typeof y;  // 10

typeof with Objects and Arrays

For complex types like objects and arrays, typeof captures their complete structural type:

const person = {
  name: "Alice",
  age: 30,
  hobbies: ["reading", "swimming"]
};

type Person = typeof person;
/* Equivalent to:
type Person = {
  name: string;
  age: number;
  hobbies: string[];
}
*/

const numbers = [1, 2, 3];
type Numbers = typeof numbers;  // number[]

typeof with Functions

typeof can also capture a function's type signature, including parameter types and return type:

function greet(name: string): string {
  return `Hello, ${name}!`;
}

type GreetFn = typeof greet;
/* Equivalent to:
type GreetFn = (name: string) => string;
*/

typeof in Type Guards

The typeof type operator can be combined with type guards to help narrow type ranges:

function padLeft(value: string | number, padding: string | number) {
  if (typeof value === "number") {
    // Here, value's type is narrowed to number
    return Array(value + 1).join(" ") + padding;
  }
  // Here, value's type is string
  return padding + value;
}

typeof with Enums

When applied to enums, typeof yields the enum's type representation:

enum Direction {
  Up,
  Down,
  Left,
  Right
}

type DirectionType = typeof Direction;
/* 
Equivalent to:
type DirectionType = {
  Up: Direction.Up;
  Down: Direction.Down;
  Left: Direction.Left;
  Right: Direction.Right;
}
*/

typeof with Classes

For classes, typeof captures the constructor type, not the instance type:

class Person {
  constructor(public name: string) {}
}

type PersonConstructor = typeof Person;
/* 
Equivalent to:
type PersonConstructor = new (name: string) => Person
*/

const createPerson = (ctor: PersonConstructor, name: string) => {
  return new ctor(name);
};

typeof with Modules

In module systems, typeof can be used to obtain the type of an imported module:

// Assume a module config.ts exists
export const config = {
  apiUrl: "https://api.example.com",
  timeout: 5000
};

// In another file
import { config } from "./config";

type AppConfig = typeof config;
/* 
Equivalent to:
type AppConfig = {
  apiUrl: string;
  timeout: number;
}
*/

Type Inference Behavior of typeof

typeof follows TypeScript's type inference rules but has some special behaviors to note:

  1. For const-declared object literals, typeof preserves all property literal types.
  2. For array literals, typeof infers a union type of array elements.
  3. For function expressions, typeof captures the complete function signature.
const obj = {
  id: 123,       // number
  name: "test"   // string
} as const;      // Using 'as const' makes all properties literal types

type ObjType = typeof obj;
/* 
Equivalent to:
type ObjType = {
  readonly id: 123;
  readonly name: "test";
}
*/

typeof with Template Strings

typeof can also be used with template string types:

const eventName = "click";
type EventHandlerName = `on${typeof eventName}`;  // "onclick"

const colors = ["red", "green", "blue"] as const;
type ColorVariants = `${typeof colors[number]}-variant`;  // "red-variant" | "green-variant" | "blue-variant"

Nested Use of typeof

typeof can be nested to obtain deeper type information:

const apiResponse = {
  data: {
    users: [
      { id: 1, name: "Alice" },
      { id: 2, name: "Bob" }
    ]
  }
};

type User = typeof apiResponse["data"]["users"][number];
/* 
Equivalent to:
type User = {
  id: number;
  name: string;
}
*/

typeof with Generics

typeof can be combined with generics for more flexible type operations:

function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

const user = { name: "Alice", age: 30 };
type AgeType = typeof user["age"];  // number

const age = getProperty(user, "age");  // Type is number

typeof in Advanced Types

In more complex type operations, typeof is often used with operators like keyof and in:

const formFields = {
  username: "",
  password: "",
  rememberMe: false
};

type FormFieldKeys = keyof typeof formFields;  // "username" | "password" | "rememberMe"
type FormFieldValues = typeof formFields[FormFieldKeys];  // string | boolean

type FormValidator = {
  [K in keyof typeof formFields]: (value: typeof formFields[K]) => boolean;
};
/* 
Equivalent to:
type FormValidator = {
  username: (value: string) => boolean;
  password: (value: string) => boolean;
  rememberMe: (value: boolean) => boolean;
}
*/

typeof and Type Queries

typeof is essentially a type query operation that allows referencing a value's type in a type position. This is particularly useful for maintaining type synchronization:

// Runtime value
const defaultConfig = {
  port: 3000,
  env: "development",
  debug: true
};

// Type stays synchronized with the value
type AppConfig = typeof defaultConfig;

function loadConfig(override: Partial<AppConfig>): AppConfig {
  return { ...defaultConfig, ...override };
}

typeof with Mapped Types

Combined with mapped types, typeof can be used to create derived types based on existing object structures:

const settings = {
  theme: "dark",
  fontSize: 14,
  autoSave: true
};

type SettingsOptions = {
  [K in keyof typeof settings]: Array<typeof settings[K]>;
};
/* 
Equivalent to:
type SettingsOptions = {
  theme: string[];
  fontSize: number[];
  autoSave: boolean[];
}
*/

Limitations of typeof

Despite its power, typeof has some limitations:

  1. Cannot be used to obtain dynamic types of runtime values.
  2. For function overloads, typeof only captures the last overload signature.
  3. In the global scope, typeof cannot be used with undeclared variables.
declare function fn(x: string): number;
declare function fn(x: number): string;

type FnType = typeof fn;  // (x: number) => string, only captures the last overload

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:keyof操作符

下一篇:索引访问类型

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.