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开发干货

相关推荐
灵感__idea5 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea7 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd8 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌9 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈9 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫9 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝9 小时前
svg图片
前端·css·学习·html·css3
橘子编程9 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇10 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧10 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint