TypeScript 接口和类型
概述
接口(Interface)和类型别名(Type Alias)是 TypeScript 中定义对象形状和类型的重要工具。它们帮助我们编写更安全、更可维护的代码。本教程将详细介绍接口和类型的使用方法。
接口基础
接口定义
// 基本接口定义
interface User {
id: number;
name: string;
email: string;
age?: number; // 可选属性
}
// 使用接口
const user: User = {
id: 1,
name: '张三',
email: 'zhangsan@example.com',
age: 25
};
// 可选属性可以省略
const user2: User = {
id: 2,
name: '李四',
email: 'lisi@example.com'
};
只读属性
interface Product {
readonly id: number;
name: string;
price: number;
readonly createdAt: Date;
}
const product: Product = {
id: 1,
name: '商品A',
price: 99.99,
createdAt: new Date()
};
// product.id = 2; // 错误:不能修改只读属性
product.price = 89.99; // 正确:可以修改非只读属性
函数类型接口
// 定义函数类型接口
interface SearchFunc {
(source: string, subString: string): boolean;
}
// 使用函数类型接口
const mySearch: SearchFunc = function(source: string, subString: string): boolean {
const result = source.search(subString);
return result > -1;
};
// 箭头函数形式
const mySearch2: SearchFunc = (source, subString) => {
return source.includes(subString);
};
可索引类型
// 字符串索引签名
interface StringArray {
[index: number]: string;
}
const myArray: StringArray = ['Bob', 'Fred'];
const myStr: string = myArray[0];
// 对象索引签名
interface StringDictionary {
[key: string]: string;
}
const dictionary: StringDictionary = {
name: '张三',
email: 'zhangsan@example.com'
};
// 混合索引签名
interface Dictionary {
[index: string]: string | number;
length: number;
name: string;
}
const dict: Dictionary = {
length: 10,
name: '字典',
key1: 'value1',
key2: 100
};
类类型接口
// 定义类接口
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
// 实现接口的类
class Clock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date) {
this.currentTime = d;
}
getTime(): Date {
return this.currentTime;
}
}
const clock = new Clock();
clock.setTime(new Date('2025-01-01'));
console.log(clock.getTime());
接口继承
// 基础接口
interface Shape {
color: string;
}
// 继承接口
interface Square extends Shape {
sideLength: number;
}
interface Rectangle extends Shape {
width: number;
height: number;
}
// 多重继承
interface ColoredSquare extends Square, Rectangle {
opacity: number;
}
const square: Square = {
color: 'red',
sideLength: 10
};
const coloredSquare: ColoredSquare = {
color: 'blue',
sideLength: 5,
width: 5,
height: 5,
opacity: 0.8
};
混合类型接口
// 混合类型:对象 + 函数
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
const counter = (function (start: number) {
return `Count: ${start}`;
}) as Counter;
counter.interval = 123;
counter.reset = function () {
console.log('Reset counter');
};
return counter;
}
const c = getCounter();
console.log(c(10));
console.log(c.interval);
c.reset();
类型别名
基本类型别名
// 基本类型别名
type Name = string;
type Age = number;
type IsActive = boolean;
// 使用类型别名
const userName: Name = '张三';
const userAge: Age = 25;
const userActive: IsActive = true;
// 对象类型别名
type User = {
id: number;
name: string;
email: string;
age?: number;
};
const user: User = {
id: 1,
name: '李四',
email: 'lisi@example.com'
};
联合类型
// 联合类型
type ID = number | string;
function printId(id: ID) {
console.log(`ID: ${id}`);
}
printId(101);
printId('2025-01-01');
// 联合类型与类型守卫
type SuccessResponse = {
status: 'success';
data: any;
};
type ErrorResponse = {
status: 'error';
error: string;
};
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(response: ApiResponse) {
if (response.status === 'success') {
console.log('数据:', response.data);
} else {
console.log('错误:', response.error);
}
}
handleResponse({ status: 'success', data: { name: '张三' } });
handleResponse({ status: 'error', error: '未找到资源' });
交叉类型
// 交叉类型
type Person = {
name: string;
age: number;
};
type Employee = {
employeeId: number;
department: string;
};
type EmployeePerson = Person & Employee;
const employee: EmployeePerson = {
name: '王五',
age: 30,
employeeId: 1001,
department: '技术部'
};
// 使用交叉类型扩展对象
type WithId = {
id: number;
};
type Timestamped = {
createdAt: Date;
updatedAt: Date;
};
type Entity = WithId & Timestamped;
const entity: Entity = {
id: 1,
createdAt: new Date(),
updatedAt: new Date()
};
泛型类型别名
// 泛型类型别名
type Container<T> = {
value: T;
};
const numberContainer: Container<number> = {
value: 42
};
const stringContainer: Container<string> = {
value: 'Hello'
};
// 复杂的泛型类型别名
type Pair<T, U> = {
first: T;
second: U;
};
const pair: Pair<string, number> = {
first: 'first',
second: 2
};
// 条件类型别名
type NonNullable<T> = T extends null | undefined ? never : T;
type MaybeString = string | null;
type DefinitelyString = NonNullable<MaybeString>; // string
映射类型
// 映射类型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type User = {
id: number;
name: string;
email: string;
};
// 只读用户
type ReadonlyUser = Readonly<User>;
const readonlyUser: ReadonlyUser = {
id: 1,
name: '张三',
email: 'zhangsan@example.com'
};
// readonlyUser.name = '李四'; // 错误
// 部分用户
type PartialUser = Partial<User>;
const partialUser: PartialUser = {
name: '李四'
};
// 必需类型
type Required<T> = {
[P in keyof T]-?: T[P];
};
type OptionalUser = {
id?: number;
name?: string;
};
type RequiredUser = Required<OptionalUser>;
const requiredUser: RequiredUser = {
id: 1,
name: '张三'
};
接口 vs 类型别名
主要区别
// 1. 接口可以扩展,类型别名不能
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// 类型别名不能这样扩展
// type Cat extends Animal { // 错误
// color: string;
// }
// 2. 类型别名可以用于联合类型和交叉类型
type ID = number | string;
type Person = { name: string } & { age: number };
// 接口不能表示联合类型
// interface ID = number | string; // 错误
// 3. 接口可以被类实现
interface Printable {
print(): void;
}
class Document implements Printable {
print() {
console.log('打印文档');
}
}
// 类型别名不能被类实现
// type Printable2 = { print(): void };
// class Document2 implements Printable2 { } // 错误
// 4. 类型别名可以用于原始类型
type Name = string;
type Age = number;
// 接口不能用于原始类型
// interface Name = string; // 错误
使用建议
// 使用接口的情况:
// 1. 定义对象的形状
interface User {
id: number;
name: string;
}
// 2. 需要扩展时
interface AdminUser extends User {
permissions: string[];
}
// 3. 需要被类实现时
interface Serializable {
serialize(): string;
}
class User implements Serializable {
serialize() {
return JSON.stringify(this);
}
}
// 使用类型别名的情况:
// 1. 联合类型
type Status = 'pending' | 'success' | 'error';
// 2. 交叉类型
type UserWithTimestamp = User & {
createdAt: Date;
updatedAt: Date;
};
// 3. 泛型类型
type Result<T> = {
data: T;
error: null;
} | {
data: null;
error: Error;
};
// 4. 映射类型
type PartialUser = Partial<User>;
// 5. 条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
高级类型
类型守卫
// typeof 类型守卫
function printValue(value: string | number) {
if (typeof value === 'string') {
console.log(`字符串: ${value.toUpperCase()}`);
} else {
console.log(`数字: ${value.toFixed(2)}`);
}
}
// instanceof 类型守卫
class Bird {
fly() {
console.log('鸟在飞');
}
}
class Fish {
swim() {
console.log('鱼在游');
}
}
function move(animal: Bird | Fish) {
if (animal instanceof Bird) {
animal.fly();
} else {
animal.swim();
}
}
// 自定义类型守卫
interface Bird {
type: 'bird';
flySpeed: number;
}
interface Fish {
type: 'fish';
swimSpeed: number;
}
function isBird(animal: Bird | Fish): animal is Bird {
return animal.type === 'bird';
}
function moveAnimal(animal: Bird | Fish) {
if (isBird(animal)) {
console.log(`鸟以 ${animal.flySpeed} km/h 的速度飞行`);
} else {
console.log(`鱼以 ${animal.swimSpeed} km/h 的速度游泳`);
}
}
可辨识联合
// 可辨识联合
interface Success {
kind: 'success';
value: string;
}
interface Error {
kind: 'error';
message: string;
}
interface Loading {
kind: 'loading';
}
type Result = Success | Error | Loading;
function handleResult(result: Result) {
switch (result.kind) {
case 'success':
console.log(`成功: ${result.value}`);
break;
case 'error':
console.log(`错误: ${result.message}`);
break;
case 'loading':
console.log('加载中...');
break;
}
}
handleResult({ kind: 'success', value: '数据加载成功' });
handleResult({ kind: 'error', message: '网络错误' });
handleResult({ kind: 'loading' });
条件类型
// 基本条件类型
type IsArray<T> = T extends any[] ? true : false;
type Test1 = IsArray<string>; // false
type Test2 = IsArray<number[]>; // true
// 条件类型中的类型推断
type Flatten<T> = T extends any[] ? T[number] : T;
type Str = Flatten<string[]>; // string
type Num = Flatten<number>; // number
// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type StrArrOrNumArr = ToArray<string | number>;
// string[] | number[]
// 条件类型约束
type MessageOf<T> = T extends { message: infer M } ? M : never;
interface Email {
message: string;
}
interface Phone {
phone: number;
}
type EmailMessage = MessageOf<Email>; // string
type PhoneMessage = MessageOf<Phone>; // never
映射修饰符
// 移除 readonly
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
interface ReadonlyUser {
readonly id: number;
readonly name: string;
}
type MutableUser = Mutable<ReadonlyUser>;
const mutableUser: MutableUser = {
id: 1,
name: '张三'
};
mutableUser.name = '李四'; // 正确
// 移除可选
type RequiredKeys<T> = {
[P in keyof T]-?: T[P];
};
interface OptionalUser {
id?: number;
name?: string;
}
type RequiredUser = RequiredKeys<OptionalUser>;
const requiredUser: RequiredUser = {
id: 1,
name: '张三'
};
// 添加 readonly
type ReadonlyKeys<T> = {
+readonly [P in keyof T]: T[P];
};
interface MutableUser {
id: number;
name: string;
}
type ReadonlyUser2 = ReadonlyKeys<MutableUser>;
const readonlyUser2: ReadonlyUser2 = {
id: 1,
name: '张三'
};
// readonlyUser2.name = '李四'; // 错误
实际应用示例
API 响应类型定义
// API 响应类型
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: {
code: number;
message: string;
};
}
// 用户类型
interface User {
id: number;
name: string;
email: string;
avatar?: string;
}
// 用户列表响应
type UserListResponse = ApiResponse<User[]>;
// 单个用户响应
type UserResponse = ApiResponse<User>;
// 使用示例
async function fetchUsers(): Promise<UserListResponse> {
const response = await fetch('/api/users');
const data: UserListResponse = await response.json();
if (data.success && data.data) {
console.log(`获取到 ${data.data.length} 个用户`);
}
return data;
}
async function fetchUser(id: number): Promise<UserResponse> {
const response = await fetch(`/api/users/${id}`);
const data: UserResponse = await response.json();
if (data.success && data.data) {
console.log(`用户: ${data.data.name}`);
}
return data;
}
表单类型定义
// 表单字段类型
interface FormField<T> {
name: string;
label: string;
value: T;
required: boolean;
error?: string;
}
// 表单类型
interface Form<T extends Record<string, any>> {
fields: {
[K in keyof T]: FormField<T[K]>;
};
validate(): boolean;
submit(): void;
}
// 用户注册表单
interface RegisterFormData {
username: string;
email: string;
password: string;
confirmPassword: string;
age: number;
}
class RegisterForm implements Form<RegisterFormData> {
fields: {
[K in keyof RegisterFormData]: FormField<RegisterFormData[K]>;
} = {
username: {
name: 'username',
label: '用户名',
value: '',
required: true
},
email: {
name: 'email',
label: '邮箱',
value: '',
required: true
},
password: {
name: 'password',
label: '密码',
value: '',
required: true
},
confirmPassword: {
name: 'confirmPassword',
label: '确认密码',
value: '',
required: true
},
age: {
name: 'age',
label: '年龄',
value: 0,
required: false
}
};
validate(): boolean {
let isValid = true;
// 验证用户名
if (!this.fields.username.value) {
this.fields.username.error = '用户名不能为空';
isValid = false;
}
// 验证邮箱
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(this.fields.email.value)) {
this.fields.email.error = '邮箱格式不正确';
isValid = false;
}
// 验证密码
if (this.fields.password.value.length < 6) {
this.fields.password.error = '密码长度至少6位';
isValid = false;
}
// 验证确认密码
if (this.fields.password.value !== this.fields.confirmPassword.value) {
this.fields.confirmPassword.error = '两次密码不一致';
isValid = false;
}
return isValid;
}
submit(): void {
if (this.validate()) {
const formData: RegisterFormData = {
username: this.fields.username.value,
email: this.fields.email.value,
password: this.fields.password.value,
confirmPassword: this.fields.confirmPassword.value,
age: this.fields.age.value
};
console.log('提交表单:', formData);
}
}
}
// 使用表单
const registerForm = new RegisterForm();
registerForm.fields.username.value = 'zhangsan';
registerForm.fields.email.value = 'zhangsan@example.com';
registerForm.fields.password.value = '123456';
registerForm.fields.confirmPassword.value = '123456';
if (registerForm.validate()) {
registerForm.submit();
}
状态管理类型
// 状态类型
interface State<T> {
data: T | null;
loading: boolean;
error: Error | null;
}
// Action 类型
type Action<T> = {
type: 'FETCH_START';
} | {
type: 'FETCH_SUCCESS';
payload: T;
} | {
type: 'FETCH_ERROR';
error: Error;
};
// Reducer 类型
type Reducer<T> = (state: State<T>, action: Action<T>) => State<T>;
// 用户状态
type UserState = State<User>;
// 用户 Reducer
const userReducer: Reducer<User> = (state, action) => {
switch (action.type) {
case 'FETCH_START':
return {
...state,
loading: true,
error: null
};
case 'FETCH_SUCCESS':
return {
...state,
loading: false,
data: action.payload,
error: null
};
case 'FETCH_ERROR':
return {
...state,
loading: false,
error: action.error
};
default:
return state;
}
};
// 初始状态
const initialState: UserState = {
data: null,
loading: false,
error: null
};
// 使用 Reducer
let currentState = initialState;
currentState = userReducer(currentState, { type: 'FETCH_START' });
console.log(currentState.loading); // true
currentState = userReducer(currentState, {
type: 'FETCH_SUCCESS',
payload: {
id: 1,
name: '张三',
email: 'zhangsan@example.com'
}
});
console.log(currentState.data); // User 对象
总结
本教程详细介绍了 TypeScript 接口和类型:
-
接口基础:
- 接口定义
- 只读属性
- 函数类型接口
- 可索引类型
- 类类型接口
- 接口继承
- 混合类型接口
-
类型别名:
- 基本类型别名
- 联合类型
- 交叉类型
- 泛型类型别名
- 映射类型
-
接口 vs 类型别名:
- 主要区别
- 使用建议
-
高级类型:
- 类型守卫
- 可辨识联合
- 条件类型
- 映射修饰符
-
实际应用:
- API 响应类型
- 表单类型定义
- 状态管理类型
接口和类型是 TypeScript 类型系统的核心,掌握它们对于编写类型安全的代码至关重要。
下一步
在下一教程中,我们将学习 TypeScript 函数和类,包括:
-
函数类型
-
类的定义和使用
-
继承和多态
-
访问修饰符
-
抽象类和接口
-
泛型类
继续学习 TypeScript,掌握这门强大语言的更多知识!

