TypeScript 接口入门:定义代码的契约与形态

一、什么是接口?

用于描述一个对象的结构。

typescript 复制代码
// 定义一个名为 User 的接口
interface User {
    id: number;
    name: string;
    email: string;
}

function printUserInfo(user: User) {
    console.log(`ID: ${user.id}, Name: ${user.name}, Email: ${user.email}`);
}

const myUser: User = {

    id: 1,
    name: 'Alice',
    email: 'alice@example.com',
};

printUserInfo(myUser); // OK

const invalidUser: User = {
    id: 2,
    username: 'Bob', // 属性名不匹配 编译时错误
    // 缺少 name,email 属性
};

二、接口的丰富特性

1. 可选属性(Optional Properties)

有时,对象的某些属性不是必需的。我们可以使用 ? 来标记它们。

typescript 复制代码
interface UserProfile {
    id: number;
    username: string;
    bio?: string; // bio 是可选的
}

const user1: UserProfile = { id: 1, username: 'Alice' }; // OK
const user2: UserProfile = { id: 2, username: 'Bob', bio: 'Developer' }; // OK

2. 只读属性(Readonly Properties)

我们可以使用 readonly 关键字来防止对象属性在创建后被修改,这对于创建不可变数据非常有用。

typescript 复制代码
interface Point {
    readonly x: number;
    readonly y: number;
}

const p1: Point = { x: 10, y: 20 };
p1.x = 5; // Error: 无法为"x"赋值,因为它是只读属性。

3. 函数类型

接口也能用来定义函数的签名(参数类型和返回值类型)。

typescript 复制代码
interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc = function (src: string, sub: string) {
    let result = src.search(sub);
    return result > -1;
};

console.log(mySearch('hello', 'll'));

4. 可索引类型(Indexable Types)

接口可以描述那些可以通过索引得到的类型,比如数组和对象。

typescript 复制代码
interface StringArray {
    [index: number]: string; // 索引是数字,值是字符串
}

let myArray: StringArray;
myArray = ['Bob', 'Fred'];
let myStr: string = myArray[0]; // OK
console.log(myStr);


interface Dictionary {
    [key: string]: any; // 索引是字符串,值是任意类型
}

let user: Dictionary = {
    name: '张三',
    age: 18,
    sex: '男',
}

console.log(user.name);

5. 类实现(Class Implementations)

接口可以被类(Class)implements(实现),强制一个类必须遵循接口定义的契约。

typescript 复制代码
interface ClockInterface {
    currentTime: Date;
    setTime(d: Date): void;
}

class Clock implements ClockInterface {
    currentTime: Date = new Date();
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) {
        this.currentTime.setHours(h);
        this.currentTime.setMinutes(m);
    }

    printTime() {
        console.log(this.currentTime.toLocaleTimeString());
    }
}


let clock = new Clock(12, 30);
clock.printTime(); //12:30:43
clock.setTime(new Date('2024-5-6 09:30:43'));
clock.printTime(); //09:30:43

三、接口的扩展与合并

1. 继承(Extends)

一个接口可以像类一样继承另一个接口,从而复用和扩展类型定义。

typescript 复制代码
interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

// Square 继承了 Shape 和 PenStroke
interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square: Square = {
    color: 'blue',
    penWidth: 5.0,
    sideLength: 10,
};

2. 声明合并(Declaration Merging)

这是一个接口独有的、非常强大的特性。如果你在同一个作用域内定义了两个同名的接口,它们会自动合并成一个单一的接口。

typescript 复制代码
interface Box {
    height: number;
    width: number;
}

interface Box {
    scale: number;
}

// 合并后,Box 接口同时拥有 height, width, 和 scale 属性
const box: Box = { height: 5, width: 6, scale: 10 };

常用的用法 扩展第三方库的类型定义。例如,如果你想为 window 对象添加一个自定义属性,你可以这样做,而不会覆盖原有的定义:

typescript 复制代码
// 在你的 .d.ts 文件中
declare global {
    interface Window {
        myAppConfig: object;
    }
}

// 现在你可以在代码中安全地访问它
window.myAppConfig = { version: '1.0' };

总结

如果你喜欢本教程,记得点赞+收藏!关注我获取更多TypeScript开发干货

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄3 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端