TypeScript 类型操作符详解

Simon Lv2

1. typeof 操作符(类型查询操作符)

功能

从 JavaScript 值中提取类型信息,获取变量、函数、对象等的类型。

定义实现

// 语法:typeof expression
type TypeOfResult = typeof someValue;

使用案例

// 基础用法
const num = 42;
type NumType = typeof num; // number

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

// 对象类型提取
const config = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
};
type ConfigType = typeof config;
// { apiUrl: string; timeout: number; retries: number }

// 函数类型提取
function add(a: number, b: number): number {
return a + b;
}
type AddFunctionType = typeof add;
// (a: number, b: number) => number

// 类构造函数类型
class User {
constructor(public name: string, public age: number) {}
}
type UserConstructor = typeof User;
// new (name: string, age: number) => User

// 复杂对象
const api = {
users: {
getAll: () => Promise<User[]>,
getById: (id: string) => Promise<User>
},
posts: {
create: (data: any) => Promise<void>
}
};
type ApiType = typeof api;

错误场景

// ❌ 错误:不能对类型使用 typeof
type MyType = { name: string };
type WrongUsage = typeof MyType; // Error: 'MyType' only refers to a type, but is being used as a value

// ❌ 错误:typeof 只能用于值
type AnotherWrong = typeof string; // Error: 'string' only refers to a type

// ✅ 正确:对值使用 typeof
const myValue: MyType = { name: "test" };
type CorrectUsage = typeof myValue; // { name: string }

2. keyof 操作符(键查询操作符)

功能

获取对象类型所有键的联合类型。

定义实现

// 语法:keyof T
type KeysOf<T> = keyof T;

使用案例

// 基础用法
interface Person {
name: string;
age: number;
email: string;
}
type PersonKeys = keyof Person; // "name" | "age" | "email"

// 数组的键
type ArrayKeys = keyof string[]; // number | "length" | "push" | "pop" | ...

// 字符串的键
type StringKeys = keyof string; // number | "charAt" | "charCodeAt" | "concat" | ...

// 实际应用:类型安全的属性访问
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}

const person: Person = { name: "Alice", age: 30, email: "alice@example.com" };
const name = getProperty(person, "name"); // string
const age = getProperty(person, "age"); // number

// 动态属性名
type DynamicKeys = keyof { [key: string]: any }; // string | number

// 与映射类型结合
type Optional<T> = {
[K in keyof T]?: T[K];
};
type OptionalPerson = Optional<Person>;
// { name?: string; age?: number; email?: string }

错误场景

// ❌ 错误:keyof 只能用于类型
const obj = { a: 1, b: 2 };
type Wrong = keyof obj; // Error: 'obj' refers to a value, but is being used as a type

// ✅ 正确:使用 typeof 先获取类型
type Correct = keyof typeof obj; // "a" | "b"

// ❌ 错误:keyof 用于非对象类型
type PrimitiveKeys = keyof number; // 实际上这是可以的,返回 number 原型上的方法名
type NeverKeys = keyof never; // never

3. extends 操作符(条件类型操作符)

功能

用于条件类型判断和泛型约束,判断一个类型是否可以赋值给另一个类型。也可以理解为,判断前者是否是后者的子类型,比如“a”就是string的子类型。

  • 为泛型做类型限制
  • 类的继承
  • 三元运算符(子类型判断)

定义实现

// 条件类型语法:T extends U ? X : Y
type Conditional<T, U, X, Y> = T extends U ? X : Y;

// 泛型约束语法:<T extends U>
type Constrained<T extends SomeType> = T;

使用案例

// 基础条件类型
type IsString<T> = T extends string ? true : false;
type Test1 = IsString<string>; // true
type Test2 = IsString<number>; // false

// 泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在可以访问 length 属性
return arg;
}
function cpmpare<T extends {length: number}>(a:T, b:T){
return a.length >= b.length ? a : b;
}

// 复杂条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
type Result = NonNullable<string | null | undefined>; // string

// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type Arrays = ToArray<string | number>; // string[] | number[]

// 嵌套条件类型
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? T[P] extends Function
? T[P]
: DeepReadonly<T[P]>
: T[P];
};


// 实际应用:类型过滤
type FilterByType<T, U> = {
[K in keyof T]: T[K] extends U ? K : never;
}[keyof T];

interface Mixed {
name: string;
age: number;
isActive: boolean;
callback: () => void;
}
type StringKeys = FilterByType<Mixed, string>; // "name"
type FunctionKeys = FilterByType<Mixed, Function>; // "callback"

错误场景

// ❌ 错误:extends 用于值而非类型
const value = "hello";
type Wrong = value extends string ? true : false; // Error

// ❌ 错误:条件类型语法错误
type BadSyntax<T> = T extends string; // Error: 条件类型需要 ? :

// ❌ 错误:泛型约束循环引用
type SelfReferencing<T extends T> = T; // Error: 类型参数 'T' 有循环约束

// ✅ 正确用法
type Correct<T> = T extends string ? true : false;
type CorrectConstraint<T extends string> = T;

分布式条件类型vs非分布式类型参数

// 情况1:分布式条件类型(有裸类型参数)
type Distributive<T> = T extends 'a' ? 'yes' : 'no';
type Result1 = Distributive<'a' | 'b' | 'c'>; // 'yes' | 'no' | 'no' = 'yes' | 'no'
// TypeScript 实际上会这样处理:
// 1. 检测到 T 是裸类型参数
// 2. 将联合类型分布到每个成员:
// - Exclude<'a', 'a'> = 'a' extends 'a' ? never : 'a' = never
// - Exclude<'b', 'a'> = 'b' extends 'a' ? never : 'b' = 'b'
// - Exclude<'c', 'a'> = 'c' extends 'a' ? never : 'c' = 'c'
// 3. 合并结果:never | 'b' | 'c' = 'b' | 'c'

// 情况2:非分布式条件类型(没有裸类型参数)
type NonDistributive = 'a' | 'b' | 'c' extends 'a' ? 'yes' : 'no'; // 'no'

// 情况3:阻止分布式行为
type PreventDistribution<T> = [T] extends ['a'] ? 'yes' : 'no';
type Result3 = PreventDistribution<'a' | 'b' | 'c'>; // 'no'

4. infer 操作符(类型推断操作符)

功能

在条件类型中推断类型,只能在条件类型的 extends 子句中使用。可以类比设参数列方程,只不过ts自动帮我们解方程。

定义实现

// 语法:T extends SomeType<infer U> ? U : never
type InferExample<T> = T extends SomeType<infer U> ? U : never;

使用案例

// 推断函数返回类型
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type FuncReturn = MyReturnType<() => string>; // string
type FuncReturn2 = MyReturnType<(x: number) => boolean>; // boolean

// 推断函数参数类型
type FirstParameter<T> = T extends (first: infer P, ...args: any[]) => any ? P : never;
type FirstParam = FirstParameter<(a: string, b: number) => void>; // string

// 推断数组元素类型
type ArrayElement<T> = T extends (infer U)[] ? U : never;
type Element = ArrayElement<string[]>; // string

// 返回嵌套Promise的值,若要支持thenable对象,可以使用PromiseLike
type MyAwaited<T> = T extends Promise<infer K> ?
K extends Promise<any> ? MyAwaited<K> : K : unknown;
type Resolved = MyAwaited<Promise<string>>; // string

// 推断对象属性类型
type PropertyType<T, K extends keyof T> = T extends { [P in K]: infer V } ? V : never;
interface User {
name: string;
age: number;
}
type NameType = PropertyType<User, "name">; // string

// 复杂推断:元组类型
type Head<T> = T extends [infer H, ...any[]] ? H : never;
type Tail<T> = T extends [any, ...infer T] ? T : never;
type HeadResult = Head<[string, number, boolean]>; // string
type TailResult = Tail<[string, number, boolean]>; // [number, boolean]

// 推断构造函数参数
type ConstructorParameters<T> = T extends new (...args: infer P) => any ? P : never;
class MyClass {
constructor(name: string, age: number) {}
}
type MyClassParams = ConstructorParameters<typeof MyClass>; // [string, number]

错误场景

// ❌ 错误:infer 只能在条件类型中使用
type Wrong<T> = infer U; // Error: 'infer' declarations are only permitted in the 'extends' clause of a conditional type

// ❌ 错误:infer 不在 extends 子句中
type AlsoWrong<T> = T extends string ? infer U : never; // Error: 'infer' 必须在 extends 子句中

// ❌ 错误:infer 变量重复声明
type Duplicate<T> = T extends [infer U, infer U] ? U : never; // Error: 重复的标识符 'U'

// ✅ 正确用法
type Correct<T> = T extends [infer U, infer V] ? [U, V] : never;
type CorrectUsage<T> = T extends (...args: any[]) => infer R ? R : never;

5. in 操作符(映射类型操作符)

功能

在映射类型中遍历联合类型的每个成员,创建新的对象类型。

定义实现

// 语法:{ [K in Keys]: ValueType }
type MappedType<T> = {
[K in keyof T]: T[K];
};

使用案例

// 基础映射类型
type MyPartial<T> = {
[P in keyof T]?: T[P];
};

interface User {
name: string;
age: number;
}
type PartialUser = MyPartial<User>; // { name?: string; age?: number }

// 映射联合类型
type StringKeys = "name" | "age" | "email";
type StringObject = {
[K in StringKeys]: string;
};
// { name: string; age: string; email: string }

// 添加修饰符
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
};
type ReadonlyUser = MyReadonly<User>; // { readonly name: string; readonly age: number }

// 移除修饰符
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};

// 条件映射
type NullableKeys<T> = {
[K in keyof T]: T[K] extends null ? K : never;
}[keyof T];

interface Mixed {
name: string;
age: number | null;
email: string | null;
}
type NullableFields = NullableKeys<Mixed>; // "age" | "email"

// 实际应用:API 响应类型转换
type ApiResponse<T> = {
[K in keyof T]: {
data: T[K];
loading: boolean;
error: string | null;
};
};

interface UserData {
profile: User;
posts: Post[];
}
type UserApiState = ApiResponse<UserData>;
// {
// profile: { data: User; loading: boolean; error: string | null };
// posts: { data: Post[]; loading: boolean; error: string | null };
// }

错误场景

// ❌ 错误:in 只能用于映射类型
type Wrong = "name" in User; // Error: 'in' 只能在映射类型中使用

// ❌ 错误:映射类型语法错误
type BadSyntax<T> = {
[K in T]: string; // Error: 如果 T 不是联合类型可能出错
};

// ❌ 错误:映射非联合类型
type MapNumber = {
[K in number]: string; // Error: 'number' 不是有效的映射类型键
};

// ✅ 正确用法
type Correct<T> = {
[K in keyof T]: T[K];
};

6. as 操作符(键重映射操作符)

功能

在映射类型中重新映射键名,可以改变属性名称。

定义实现

// 语法:{ [K in keyof T as NewKeyType]: ValueType }
type RemappedType<T> = {
[K in keyof T as `new_${string & K}`]: T[K];
};

使用案例

// 基础键重映射
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

interface User {
name: string;
age: number;
}
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }

// 条件键重映射
type PickByType<T, U> = {
[K in keyof T as T[K] extends U ? K : never]: T[K];
};

interface Mixed {
name: string;
age: number;
isActive: boolean;
callback: () => void;
}
type StringProps = PickByType<Mixed, string>; // { name: string }
type FunctionProps = PickByType<Mixed, Function>; // { callback: () => void }

// 复杂重映射:添加前缀后缀
type EventHandlers<T> = {
[K in keyof T as `on${Capitalize<string & K>}Changed`]: (value: T[K]) => void;
};
type UserEventHandlers = EventHandlers<User>;
// { onNameChanged: (value: string) => void; onAgeChanged: (value: number) => void }

// 过滤和转换
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];

type NonFunctionProperties<T> = {
[K in NonFunctionPropertyNames<T>]: T[K];
};

// 实际应用:表单状态管理
type FormState<T> = {
[K in keyof T as `${string & K}State`]: {
value: T[K];
error: string | null;
touched: boolean;
};
};

interface LoginForm {
username: string;
password: string;
}
type LoginFormState = FormState<LoginForm>;
// {
// usernameState: { value: string; error: string | null; touched: boolean };
// passwordState: { value: string; error: string | null; touched: boolean };
// }

错误场景

// ❌ 错误:as 用于非映射类型
type Wrong = string as number; // Error: 这是类型断言,不是键重映射

// ❌ 错误:as 重映射语法错误
type BadSyntax<T> = {
[K in keyof T]: T[K] as string; // Error: as 应该用于键,不是值
};

// ❌ 错误:重映射到非有效键类型
type InvalidKey<T> = {
[K in keyof T as T[K]]: string; // Error: T[K] 可能不是有效的键类型
};

// ✅ 正确用法
type Correct<T> = {
[K in keyof T as `prefix_${string & K}`]: T[K];
};

7. [] 操作符(索引访问操作符)

功能

通过索引获取对象类型的属性类型或数组类型的元素类型。

定义实现

// 语法:T[K] 或 T[number] 或 T[keyof T]
type IndexAccess<T, K extends keyof T> = T[K];

使用案例

// 基础索引访问
interface Person {
name: string;
age: number;
address: {
city: string;
country: string;
};
}

type Name = Person["name"]; // string
type Age = Person["age"]; // number
type Address = Person["address"]; // { city: string; country: string }
type City = Person["address"]["city"]; // string

// 数组索引访问
type StringArray = string[];
type ArrayElement = StringArray[number]; // string

// 元组索引访问
type Tuple = [string, number, boolean];
type First = Tuple[0]; // string
type Second = Tuple[1]; // number
type Third = Tuple[2]; // boolean

// 联合索引访问
type NameOrAge = Person["name" | "age"]; // string | number

// 所有属性类型的联合
type AllPersonValues = Person[keyof Person]; // string | number | { city: string; country: string }

// 实际应用:深度访问
type DeepGet<T, K extends string> = K extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? DeepGet<T[Key], Rest>
: never
: K extends keyof T
? T[K]
: never;

type DeepCity = DeepGet<Person, "address.city">; // string

// 数组元素类型提取
type ArrayElementType<T> = T extends (infer U)[] ? U : never;
type ElementType = ArrayElementType<Person[]>; // Person

// 函数参数类型提取
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
type FunctionParams = Parameters<(a: string, b: number) => void>; // [string, number]
type FirstParam = FunctionParams[0]; // string

错误场景

// ❌ 错误:索引不存在
type Wrong = Person["nonExistent"]; // Error: Property 'nonExistent' does not exist on type 'Person'

// ❌ 错误:索引类型不匹配
type AlsoWrong = Person[123]; // Error: 123 不是 Person 的有效索引

// ❌ 错误:对非对象类型使用索引
type BadIndex = string["length"]; // 实际上这是可以的,返回 number

// ❌ 错误:动态索引访问
const key = "name";
type DynamicWrong = Person[key]; // Error: 'key' 不能用作索引

// ✅ 正确用法
type Correct = Person["name"];
type CorrectUnion = Person["name" | "age"];
type CorrectDynamic<K extends keyof Person> = Person[K];

8. | 操作符(联合类型操作符)

功能

创建联合类型,表示一个值可以是多种类型中的任意一种。

定义实现

// 语法:T | U | V
type Union<T, U> = T | U;

使用案例

// 基础联合类型
type StringOrNumber = string | number;
type Status = "loading" | "success" | "error";

// 函数参数联合类型
function process(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value.toString();
}
}

// 对象联合类型
type Circle = {
kind: "circle";
radius: number;
};

type Rectangle = {
kind: "rectangle";
width: number;
height: number;
};

type Shape = Circle | Rectangle;

function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
}
}

// 联合类型的分布式行为
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>; // string[] | number[]

// 实际应用:API 响应类型
type ApiResponse<T> =
| { success: true; data: T }
| { success: false; error: string };

type UserResponse = ApiResponse<User>;
// { success: true; data: User } | { success: false; error: string }

// 联合类型工具函数
type Extract<T, U> = T extends U ? T : never;
type StringFromUnion = Extract<string | number | boolean, string>; // string

type Exclude<T, U> = T extends U ? never : T;
type NonString = Exclude<string | number | boolean, string>; // number | boolean

错误场景

// ❌ 错误:访问联合类型的非共同属性
type Union = { a: string } | { b: number };
type Wrong = Union["a"]; // Error: Property 'a' does not exist on type '{ b: number }'

// ❌ 错误:不正确的类型守卫
function badGuard(value: string | number) {
return value.toUpperCase(); // Error: Property 'toUpperCase' does not exist on type 'number'
}

// ✅ 正确用法:类型守卫
function goodGuard(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toString();
}

// ✅ 正确用法:访问共同属性
type CommonUnion = { common: string; a: number } | { common: string; b: boolean };
type Common = CommonUnion["common"]; // string

9. & 操作符(交叉类型操作符)

功能

创建交叉类型,将多个类型合并为一个类型,包含所有类型的属性。

定义实现

// 语法:T & U & V
type Intersection<T, U> = T & U;

使用案例

// 基础交叉类型
type Person = {
name: string;
age: number;
};

type Employee = {
id: number;
department: string;
};

type PersonEmployee = Person & Employee;
// { name: string; age: number; id: number; department: string }

// 函数类型交叉
type Logger = {
log: (message: string) => void;
};

type Counter = {
count: number;
increment: () => void;
};

type LoggerCounter = Logger & Counter;
const loggerCounter: LoggerCounter = {
log: (message) => console.log(message),
count: 0,
increment() {
this.count++;
this.log(`Count is now ${this.count}`);
}
};

// Mixin 模式
type Timestamped = {
timestamp: Date;
};

type Versioned = {
version: number;
};

type Document = {
title: string;
content: string;
};

type VersionedDocument = Document & Timestamped & Versioned;

// 实际应用:配置对象合并
type BaseConfig = {
apiUrl: string;
timeout: number;
};

type DevConfig = {
debug: boolean;
mockData: boolean;
};

type ProductionConfig = {
analytics: boolean;
errorReporting: boolean;
};

type AppConfig = BaseConfig & (DevConfig | ProductionConfig);

// 条件交叉类型
type AddTimestamp<T> = T & { timestamp: Date };
type TimestampedUser = AddTimestamp<Person>;
// { name: string; age: number; timestamp: Date }

// 工具类型与交叉类型
type Override<T, U> = Omit<T, keyof U> & U;
type UpdatedPerson = Override<Person, { age: string }>; // { name: string; age: string }

错误场景

// ❌ 错误:冲突的属性类型
type Conflict = { prop: string } & { prop: number };
// 这会创建一个 prop: string & number 的类型,实际上是 never

// ❌ 错误:不兼容的函数签名
type FunctionConflict = ((x: string) => void) & ((x: number) => void);
// 这会创建一个不可调用的函数类型

// ❌ 错误:原始类型交叉
type PrimitiveIntersection = string & number; // never

// ✅ 正确用法:兼容的属性类型
type CompatibleIntersection = { a: string } & { b: number }; // { a: string; b: number }

// ✅ 正确用法:函数重载
type OverloadedFunction = {
(x: string): string;
(x: number): number;
};

10. is 操作符(类型谓词操作符)

功能

创建类型谓词函数,用于类型守卫,帮助 TypeScript 进行类型收窄。

定义实现

// 语法:parameterName is Type
function isType(value: unknown): value is SomeType {
// 类型检查逻辑
return /* boolean expression */;
}

使用案例

// 基础类型谓词
function isString(value: unknown): value is string {
return typeof value === "string";
}

function isNumber(value: unknown): value is number {
return typeof value === "number";
}

// 使用类型谓词
function processValue(value: unknown): string {
if (isString(value)) {
return value.toUpperCase(); // TypeScript 知道这里 value 是 string
}
if (isNumber(value)) {
return value.toString(); // TypeScript 知道这里 value 是 number
}
return "unknown";
}

// 复杂对象类型谓词
interface User {
name: string;
age: number;
}

function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"name" in value &&
"age" in value &&
typeof (value as any).name === "string" &&
typeof (value as any).age === "number"
);
}

// 数组类型谓词
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === "string");
}

// 实际应用:API 数据验证
interface ApiUser {
id: number;
name: string;
email: string;
}

function isApiUser(data: unknown): data is ApiUser {
return (
typeof data === "object" &&
data !== null &&
"id" in data &&
"name" in data &&
"email" in data &&
typeof (data as any).id === "number" &&
typeof (data as any).name === "string" &&
typeof (data as any).email === "string"
);
}

async function fetchUser(id: number): Promise<ApiUser> {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();

if (isApiUser(data)) {
return data; // TypeScript 知道这是 ApiUser
}

throw new Error("Invalid user data");
}

// 联合类型分辨
type Animal =
| { type: "cat"; meow: () => void }
| { type: "dog"; bark: () => void };

function isCat(animal: Animal): animal is { type: "cat"; meow: () => void } {
return animal.type === "cat";
}

function handleAnimal(animal: Animal) {
if (isCat(animal)) {
animal.meow(); // TypeScript 知道这是 cat
} else {
animal.bark(); // TypeScript 知道这是 dog
}
}

错误场景

// ❌ 错误:类型谓词与实际逻辑不匹配
function badIsString(value: unknown): value is string {
return typeof value === "number"; // 逻辑错误,但编译器不会报错
}

// ❌ 错误:类型谓词参数错误
function wrongParameter(value: unknown): otherValue is string { // Error: 'otherValue' 未定义
return typeof value === "string";
}

// ❌ 错误:类型谓词返回类型错误
function badReturnType(value: unknown):
  • 标题: TypeScript 类型操作符详解
  • 作者: Simon
  • 创建于 : 2025-09-11 11:48:11
  • 更新于 : 2025-09-11 11:49:48
  • 链接: https://www.simonicle.cn/2025/09/11/TypeScript 类型操作符详解/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论