The `typeof` type operator
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:
- For
const
-declared object literals,typeof
preserves all property literal types. - For array literals,
typeof
infers a union type of array elements. - 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:
- Cannot be used to obtain dynamic types of runtime values.
- For function overloads,
typeof
only captures the last overload signature. - 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