常用语法
1. 基本类型注解
TypeScript 的核心是类型系统,基本类型注解是最常见的使用方式。
// 基本类型
let name: string = "Alice";
let age: number = 25;
let isActive: boolean = true;
// 数组
let numbers: number[] = [1, 2, 3];
// 或者使用泛型形式
let strings: Array<string> = ["a", "b", "c"];
// 对象
let person: { name: string; age: number } = { name: "Bob", age: 30 };
实用场景:明确变量类型,避免类型错误,尤其在团队协作中。
2. 接口 (Interface)
接口是定义对象结构的常用方式,可复用且支持扩展。
interface User {
name: string;
age: number;
email?: string; // 可选属性
}
// 使用接口
const user: User = { name: "Charlie", age: 28 };
// 接口扩展
interface Admin extends User {
role: string;
}
const admin: Admin = { name: "Dave", age: 35, role: "admin" };
实用场景:定义 API 返回数据结构、组件 props 类型等。
3. 泛型 (Generics)
泛型让函数或类在类型上更灵活,同时保持类型安全。
// 泛型函数
function getFirst<T>(array: T[]): T | undefined {
return array[0];
}
const firstNum = getFirst<number>([1, 2, 3]); // 1
const firstStr = getFirst<string>(["a", "b", "c"]); // "a"
// 泛型接口
interface Response<T> {
data: T;
status: number;
}
const userResponse: Response<{ name: string }> = {
data: { name: "Eve" },
status: 200,
};
实用场景:编写可重用的工具函数、处理不同类型的 API 响应。
4. 联合类型 (Union Types) 和类型别名 (Type Alias)
联合类型和类型别名让类型更灵活。
// 联合类型
type ID = string | number;
let userId: ID = "abc123";
userId = 123; // 也合法
// 类型别名
type Status = "success" | "error" | "loading";
let currentStatus: Status = "loading";
实用场景:处理多种可能的值(如状态管理)或简化复杂类型。
5. 工具类型 (Utility Types)
TypeScript 内置了一些实用工具类型,简化类型操作。
// Partial:将所有属性变为可选
interface Todo {
title: string;
completed: boolean;
}
const partialTodo: Partial<Todo> = { title: "Learn TS" };
// Pick:挑选部分属性
type TodoPreview = Pick<Todo, "title">;
const preview: TodoPreview = { title: "Learn TS" };
// Omit:排除部分属性
type TodoWithoutCompleted = Omit<Todo, "completed">;
const todo: TodoWithoutCompleted = { title: "Learn TS" };
// ReturnType:获取函数返回类型
function getUser() {
return { name: "Frank", age: 40 };
}
type UserType = ReturnType<typeof getUser>; // { name: string; age: number }
实用场景:操作已有类型,减少重复定义。
6. 类型断言 (Type Assertion)
当你比 TypeScript 更清楚变量类型时,可以使用类型断言。
let someValue: any = "this is a string";
// 使用 as 断言
let strLength: number = (someValue as string).length;
// 非空断言 (!)
let element: HTMLElement | null = document.querySelector("#app");
let app = element!.innerText; // 确定 element 不为 null
实用场景:处理不确定类型的数据(如 DOM 操作或第三方库)。
7. 枚举 (Enums)
枚举用于定义一组命名常量,增强代码可读性。
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
let move: Direction = Direction.Up; // "UP"
实用场景:定义有限的选项(如状态码、方向)。
8. 类型守卫 (Type Guards)
通过条件判断收窄类型范围。
function isString(value: any): value is string {
return typeof value === "string";
}
function process(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase()); // value 被收窄为 string
} else {
console.log(value.toFixed(2)); // value 被收窄为 number
}
}
实用场景:处理联合类型时确保类型安全。
9. 模块化和类型声明
为第三方库或纯 JS 文件提供类型支持。
// declare 声明全局变量
declare const myGlobalVar: string;
// 为无类型的模块添加类型
declare module "some-npm-package" {
export function doSomething(): string;
}
实用场景:集成无类型支持的库。
10. 条件类型 (Conditional Types)
条件类型让类型更动态。
type IsString<T> = T extends string ? "yes" : "no";
type Test1 = IsString<string>; // "yes"
type Test2 = IsString<number>; // "no"
实用场景:高级类型推导,编写复杂类型逻辑。
总结
这些用法涵盖了 TypeScript 的核心特性:
- 类型安全:基本类型、接口、类型守卫。
- 灵活性:泛型、工具类型、条件类型。
- 可维护性:枚举、类型别名、模块化。
函数类型声明
1. 直接声明函数的类型
为函数变量或参数直接指定类型,使用 (参数: 类型) => 返回值类型
的语法。
// 函数类型声明
let add: (a: number, b: number) => number;
// 赋值实现
add = (a, b) => a + b;
console.log(add(2, 3)); // 输出: 5
要点:
- 参数类型和返回类型用箭头
=>
分隔。 - 如果函数没有返回值,可以用
void
。
let log: (message: string) => void;
log = (message) => console.log(message);
2. 在接口或类型别名中声明函数类型
使用 interface
或 type
定义函数类型,常用于描述对象属性或复杂结构。
用 interface
:
interface MathOperation {
(x: number, y: number): number;
}
const multiply: MathOperation = (x, y) => x * y;
console.log(multiply(4, 5)); // 输出: 20
用 type
:
type Greet = (name: string) => string;
const sayHello: Greet = (name) => `Hello, ${name}`;
console.log(sayHello("Alice")); // 输出: "Hello, Alice"
区别:
interface
更适合定义对象结构,可扩展。type
更灵活,适合简单类型或联合类型。
3. 函数参数和返回值类型的推断
如果函数实现时直接指定了参数和返回值的类型,TypeScript 可以自动推断类型,无需显式声明函数类型。
const subtract = (a: number, b: number): number => a - b;
// 类型自动推断为 (a: number, b: number) => number
console.log(subtract(10, 7)); // 输出: 3
但如果函数类型需要复用或传递,建议显式声明。
4. 可选参数和默认参数
函数参数可以是可选的(用 ?
)或带默认值。
// 可选参数
type PrintInfo = (name: string, age?: number) => void;
const printInfo: PrintInfo = (name, age) => {
console.log(`Name: ${name}${age ? `, Age: ${age}` : ""}`);
};
printInfo("Bob"); // 输出: "Name: Bob"
printInfo("Bob", 30); // 输出: "Name: Bob, Age: 30"
// 默认参数
type GreetWithDefault = (name: string, greeting?: string) => string;
const greet: GreetWithDefault = (name, greeting = "Hi") => `${greeting}, ${name}`;
console.log(greet("Charlie")); // 输出: "Hi, Charlie"
注意:可选参数必须放在必选参数后面。
5. 剩余参数 (Rest Parameters)
使用 ...
表示剩余参数,类型为数组。
type Sum = (...numbers: number[]) => number;
const sum: Sum = (...numbers) => numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum(1, 2, 3, 4)); // 输出: 10
6. 函数重载 (Function Overloads)
当函数根据参数类型返回不同类型时,可以使用函数重载。
function convert(input: string): number;
function convert(input: number): string;
function convert(input: string | number): string | number {
if (typeof input === "string") return parseInt(input);
return input.toString();
}
const num = convert("123"); // 类型: number
const str = convert(456); // 类型: string
要点:
- 重载签名写在实现签名之前。
- 实现签名需兼容所有重载。
7. 回调函数类型
在函数参数中声明回调函数的类型。
function fetchData(callback: (data: string) => void): void {
const data = "Some data";
callback(data);
}
fetchData((data) => console.log(data)); // 输出: "Some data"
实用场景:异步操作、事件处理。
8. 泛型函数类型
为函数添加泛型,增强灵活性。
type IdentityFn<T> = (value: T) => T;
const identity: IdentityFn<number> = (value) => value;
console.log(identity(42)); // 输出: 42
// 直接在函数定义中使用泛型
function map<T, U>(array: T[], transform: (item: T) => U): U[] {
return array.map(transform);
}
const lengths = map(["a", "bc"], (s) => s.length); // 类型: number[]
实用场景:处理动态类型,如数组操作。
9. 异步函数类型
异步函数返回 Promise
,需指定返回值的类型。
type AsyncFn = (id: number) => Promise<string>;
const getData: AsyncFn = async (id) => {
return `Data for id ${id}`;
};
getData(1).then(console.log); // 输出: "Data for id 1"
总结
以下是函数类型声明的常用方式及其适用场景:
- 直接类型声明:简单函数变量。
- 接口/类型别名:复用函数签名。
- 泛型:动态类型处理。
- 重载:多类型返回。
- 异步:Promise 返回值。
联合类型、交叉类型
1. 联合类型 (Union Types)
定义
联合类型表示一个值可以是多种类型中的一种,用 |
分隔不同类型。
语法
type UnionType = Type1 | Type2 | Type3;
示例
type Status = "success" | "error" | "loading";
let currentStatus: Status = "success"; // 合法
currentStatus = "error"; // 合法
// currentStatus = "pending"; // 错误: 类型不匹配
// 联合类型与基本类型
type ID = string | number;
let userId: ID = "abc123";
userId = 123; // 都合法
特点
- 类型收窄:使用类型守卫(如
typeof
、in
、自定义守卫)区分具体类型。 - 只能访问公共成员:当使用联合类型时,只能访问所有类型共有的属性或方法。
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase()); // id 被收窄为 string
} else {
console.log(id.toFixed(2)); // id 被收窄为 number
}
}
printId("hello"); // 输出: "HELLO"
printId(123.456); // 输出: "123.46"
实用场景
- 表示变量可能有多种类型(如函数参数、API 返回值)。
- 定义有限的选项(如状态枚举)。
2. 交叉类型 (Intersection Types)
定义
交叉类型表示一个值同时具有多种类型的特性,用 &
组合多个类型。
语法
type IntersectionType = Type1 & Type2 & Type3;
示例
interface Person {
name: string;
}
interface Employee {
id: number;
}
type Staff = Person & Employee;
const staff: Staff = {
name: "Alice",
id: 1001,
}; // 必须同时满足 Person 和 Employee
特点
- 合并类型:交叉类型将多个类型的成员合并为一个新类型。
- 属性要求:值必须具备所有类型的属性。
- 与对象类型更相关:交叉类型通常用于对象类型,基本类型交叉可能导致
never
。
type A = { a: string };
type B = { b: number };
type AB = A & B;
const obj: AB = { a: "hello", b: 42 }; // 必须同时有 a 和 b
基本类型交叉
当交叉类型应用于不相容的基本类型时,结果可能是 never
(无任何值能满足)。
type StrAndNum = string & number; // 类型为 never,因为 string 和 number 无交集
let value: StrAndNum; // 无法赋值任何值
实用场景
- 合并多个接口(如描述一个对象同时具有多种角色)。
- 在类型系统中扩展已有类型。
3. 联合类型 vs 交叉类型
| 特性 | 联合类型 (Union) |
| 交叉类型 (Intersection) &
|
|------------------|------------------------------|------------------------------|
| 含义 | “或”关系,可以是任一类型 | “与”关系,必须同时满足所有类型 |
| 语法 | A \| B
| A & B
|
| 结果 | 值是 A 或 B 中的一种 | 值同时具有 A 和 B 的特性 |
| 典型使用 | 表示多种可能 | 合并类型特性 |
| 访问限制 | 只能访问公共成员 | 可访问所有成员 |
| 示例 | string \| number
| {a: string} & {b: number}
|
对比示例
// 联合类型
type Union = { a: string } | { b: number };
const unionValue: Union = { a: "foo" }; // 合法
const unionValue2: Union = { b: 123 }; // 合法
// const unionValue3: Union = { a: "foo", b: 123 }; // 可行,但不是必须
// 交叉类型
type Intersection = { a: string } & { b: number };
const intersectionValue: Intersection = { a: "foo", b: 123 }; // 必须同时有 a 和 b
// const intersectionValue2: Intersection = { a: "foo" }; // 错误,缺少 b
4. 高级用法
联合类型与类型守卫
function process(value: string | number | boolean) {
if (typeof value === "string") {
return value.toUpperCase();
} else if (typeof value === "number") {
return value * 2;
} else {
return !value;
}
}
交叉类型与泛型
type Merge<T, U> = T & U;
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
type CatDog = Merge<Cat, Dog>;
const pet: CatDog = {
meow: () => console.log("Meow"),
bark: () => console.log("Woof"),
};
pet.meow(); // "Meow"
pet.bark(); // "Woof"
条件类型中的联合与交叉
type Check<T> = T extends string ? "string" : "other";
type Result = Check<string | number>; // "string" | "other"
type Combine<T, U> = T & U;
type Combined = Combine<{ a: string }, { b: number }>; // { a: string; b: number }
5. 注意事项
- 联合类型的歧义:如果联合类型成员没有公共方法,访问时需类型收窄。
- 交叉类型的冲突:如果交叉的类型有同名属性但类型不同,结果可能是
never
。
type Conflict = { x: string } & { x: number }; // x 的类型为 never
总结
- 联合类型:适用于“或”的场景,表示多种可能之一。
- 交叉类型:适用于“与”的场景,合并多种特性。
extends 主要使用场景
1. 接口继承 (Interface Extension)
定义
extends
用于让一个接口继承另一个接口的属性,扩展已有类型定义。
示例
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: string;
}
const employee: Employee = {
name: "Alice",
age: 30,
employeeId: "E123",
};
使用场景
- 扩展对象类型:当需要在已有接口基础上添加新属性时。
- 代码复用:避免重复定义公共属性。
- 实用例子:定义 React 组件的 props 类型时,扩展基础 props。
interface BaseProps {
className: string;
}
interface ButtonProps extends BaseProps {
onClick: () => void;
}
2. 类继承 (Class Inheritance)
定义
extends
用于类继承,让子类继承父类的属性和方法。
示例
class Animal {
move() {
console.log("Moving...");
}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
const dog = new Dog();
dog.move(); // "Moving..."
dog.bark(); // "Woof!"
使用场景
- 面向对象编程:实现类的层次结构。
- 复用逻辑:父类的公共方法或属性可以被子类直接使用。
- 实用例子:定义不同类型的控制器类,继承基础功能。
3. 泛型约束 (Generic Constraint)
定义
extends
用于约束泛型参数的类型,要求泛型类型必须符合某个条件(如具有特定属性)。
示例
interface HasLength {
length: number;
}
function getLength<T extends HasLength>(item: T): number {
return item.length;
}
console.log(getLength("hello")); // 5
console.log(getLength([1, 2, 3])); // 3
// getLength(42); // 错误: number 没有 length 属性
使用场景
- 限制类型范围:确保泛型参数具有特定属性或方法。
- 类型安全:避免传入不符合预期的类型。
- 实用例子:处理特定结构的数组或对象。
interface Printable {
print(): void;
}
function logItem<T extends Printable>(item: T) {
item.print();
}
4. 条件类型 (Conditional Types)
定义
extends
在条件类型中用于类型推断和分发,语法为 T extends U ? X : Y
,表示如果 T
是 U
的子集,则结果为 X
,否则为 Y
。
示例
type IsString<T> = T extends string ? "yes" : "no";
type Test1 = IsString<string>; // "yes"
type Test2 = IsString<number>; // "no"
分发行为(联合类型)
当 T
是联合类型时,extends
会对每个成员分别应用条件。
type Check<T> = T extends string ? "string" : "other";
type Result = Check<string | number>; // "string" | "other"
使用场景
- 类型推断:根据条件动态生成类型。
- 类型过滤:从联合类型中提取特定类型。
- 实用例子:工具类型(如
Extract
、Exclude
)的实现。
type ExtractString<T> = T extends string ? T : never;
type StringsOnly = ExtractString<string | number | boolean>; // string
5. 类型兼容性检查
定义
extends
可以用来检查一个类型是否兼容另一个类型,尤其在高级类型操作中。
示例
type Animal = { name: string };
type Dog = { name: string; breed: string };
type IsDogAnimal = Dog extends Animal ? "yes" : "no"; // "yes"
// 因为 Dog 的结构包含 Animal 的所有属性
使用场景
- 类型关系验证:判断类型之间的子集关系。
- 高级工具类型:如
keyof
、infer
结合使用。
6. ** keyof 和 extends 结合**
定义
extends
常与 keyof
一起使用,约束键的范围。
示例
interface User {
name: string;
age: number;
}
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = { name: "Bob", age: 25 };
console.log(getProperty(user, "name")); // "Bob"
// getProperty(user, "email"); // 错误: "email" 不是 User 的键
使用场景
- 安全访问对象属性:确保键名有效。
- 实用例子:工具函数中动态获取属性。
7. extends 在映射类型中
定义
在映射类型中,extends
约束键的来源。
示例
type Optional<T> = {
[K in keyof T]?: T[K];
};
interface Config {
host: string;
port: number;
}
type OptionalConfig = Optional<Config>;
// { host?: string; port?: number }
使用场景
- 类型转换:生成新类型(如所有属性可选、可为空)。
- 实用例子:处理配置对象。
总结
extends
的主要使用场景包括:
场景 | 作用 | 示例类型/关键字 |
---|---|---|
接口继承 | 扩展接口属性 | interface |
类继承 | 实现类的继承 | class |
泛型约束 | 限制泛型类型范围 | <T extends U> |
条件类型 | 动态决定类型 | T extends U ? X : Y |
类型兼容性 | 检查类型子集关系 | 条件类型 |
keyof 约束 | 限制键的范围 | K extends keyof T |
映射类型 | 控制映射键的来源 | [K in keyof T] |
实用建议
- 简单场景:用接口或类继承扩展类型。
- 复杂场景:结合泛型和条件类型实现动态逻辑。
- 类型安全:用约束和
keyof
防止错误。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)