第四章 接口和类型兼容性

接口

TS中的接口(Interface)是用于约束类、对象、函数的规范

接口定义语句不会出现在编译结果中

约束对象

使用Interface关键字定义接口

ts 复制代码
// 定义用户接口,要求每一个用户对象中必须包含一个name字符串属性和一个age数字属性
interface User {
    name: string
    age: number
}

类似于对象类型约束

ts 复制代码
type User = {
       name: string,
       age: number
}

约束函数

函数可以是单独的函数,也可以作为对象的属性,即方法

约束单独的函数:

ts 复制代码
interface Condition {					// 这里的大括号是划分接口定义代码的符号,不是要求Condition为对象
    (n: number): boolean
}

function sum(nums:number[], callback: Condition){
    let result = 0;
    nums.forEach((num)=>{
        if(callback(num)){
            result += num;
        }
	});
}

类似于

ts 复制代码
// 定义sum函数,函数接收一个数字数组和一个回调函数,数组元素只有满足回调函数中的条件时,才会参与求和

type Condition = (n:number)=>boolean;

// 下面同上
// type Condition = {
//     (n: number): boolean
// }

function sum(nums:number[], callback: Condition){}

约束方法:

ts 复制代码
interface User {
    // sayHello是一个函数(方法),方法不接收任何参数,不返回任何值
    sayHello: ()=>void
    // 等同下面的写法
    sayHello():void
}

继承

接口继承了其他接口,子接口中会自动包含父接口的字段类型限制

ts 复制代码
interface A {
    a: number
}

interface B extends A {
    b: string
}

let b: B = {
    a: 1,
    b: "2"
}

接口允许多继承

ts 复制代码
interface A {
    a: number
}

interface B {
    b: string
}

interface C extends A, B {
    c: boolean
}

let c: C = {
    a: 1,
    b: "2",
    c: true
}

子接口中不允许出现和父接口同名且类型不同的字段

ts 复制代码
interface A {
    a: number
}

interface B {
    b: string
}

interface C extends A, B {
    a: string						// 与父接口A中的a字段类型冲突,不允许
    b: string						// 与付接口B中的b字段类型不冲突,允许
    c: boolean
}

let c: C = {
    a: 1,
    b: "2",
    c: true
}

可选属性

约束属性时加上?,表示该属性可以为undefined

ts 复制代码
interface User {
	name: string			// 必须存在
    height?: number			// 等同于 height: number|undefined
}

readonly

被readonly修饰符修饰的目标是只读的

支持修饰对象成员以及数组、元组类型

修饰成员,成员初始化后就不允许被修改

ts 复制代码
interface User {
	readonly id: string
}

const user = {
    id: "1"
};

user.id = "2";			// ❌️

修饰数组&元组字面量类型,引用类型中的内容就不允许修改

ts 复制代码
const arr: readonly number[] = [1, 2, 3];
// 等同于
const arr: ReadonlyArray<number> = [1, 2, 3];

arr.push();				// ❌️
arr[0] = -1;			// ❌️

只读修饰符只参与编译,不会出现在编译结果中

类型兼容性

如果一个变量(或字面量)能够赋值给另一个变量,则说明这两者的类型是兼容的

不同类型的兼容性策略有所不同:

  • 基本类型:完全匹配,例如不能将boolean类型的值赋值给被string类型约束的变量

  • 对象类型:引用类型的类型兼容型根据赋的值的不同有不同的处理

    将一个变量赋值给另一个变量时,会采用子结构辩型法进行类型判断,目标类型包含一些特征,如果被赋予的值满足了所有特征,那么两者就是兼容的

    ts 复制代码
    interface Duck {
        sound: "嘎嘎嘎",				// 特征1: 拥有sound属性,为"嘎嘎嘎"字面量类型
        swim(): void					// 特征2: 拥有swim方法,方法不接收参数也不返回内容
    }
    
    const person = {
        name: "伪装成鸭子的人",
        age: 20,
        sound: "嘎嘎嘎" as "嘎嘎嘎",				// 类型断言
        swim(){
            console.log(this.name + "正在游泳,并发出了【" + this.sound + "】的声音");
        }
    }
    
    const duck:Duck = person;					// 因为person满足Duck类型的所有特征,因此允许将person赋值给duck

    直接将字面量赋值给变量时,会进行更加严格的检查

    ts 复制代码
    interface Duck {
        sound: "嘎嘎嘎",
        swim(): void
    }
    
    const duck:Duck = {							// 虽然对象字面量满足Duck类型的所有特征,但由于是字面量赋值,所以不允许字面量中出现sound和swim以外的其他属性
        name: "伪装成鸭子的人",
        age: 20,
        sound: "嘎嘎嘎" as "嘎嘎嘎",
        swim(){
            console.log(this.name + "正在游泳,并发出了【" + this.sound + "】的声音");
        }
    }

    使用字面量赋值一定是有意为之的,因为编码是一定知道变量的类型和值的类型具体类型,此时就应该更严格地进行约束

    而第三方变量可能是接口获取或其他方式获取得到的,第三方变量可能并不能确定被赋值的变量的类型,因此降低了约束范围

  • 函数类型:函数类型的约束主要体现在两个方面,参数和返回值

    参数:被赋值的函数字面量的形参数量可以少于(但不能多)函数类型规定的形参数量(这也符合的开发习惯,因为并不是所有的参数都一定需要使用到)

    ts 复制代码
    interface Condition {
        (num: number, index: number): boolean
    }
    
    function sum(nums, callback: Condition){
    	let result = 0;
        nums.forEach((num, index)=>{
            if(callback(num, index)){
                result += num;
            }
        });
        return result;
    }
    
    sum([1, 2, 3, 4, 5], (num)=>{					// 正确
        return num > 3;
    });
    
    sum([1, 2, 3, 4, 5], (num, index)=>{			// 正确
        return index > 3;
    });

    返回值:如果不要求返回内容,则函数定义时可返回也可不返回;如果要求返回内容,则实际的返回值必须满足返回类型的要求

类型断言

如果确定某个变量的值属于某个类型,但是TS对该变量的类型的推断又有问题,那么就可以使用类型断言

ts 复制代码
type Test = "test";

const str = "test";
// 正常情况下,TS会识别str为字符串类型,但实际上它是"test"字面量类型,此时就可以使用类型断言
const str = "test" as Test;
// 或者
const str = <Test>"test";
相关推荐
慧一居士1 小时前
Sass和Less功能、使用场景、用法对比
前端·css·less·sass
leoZ2311 小时前
AI+前端提效-09 AI赋能前端测试:单元测试、E2E测试自动生成,提升覆盖率
前端·人工智能·opencv·目标检测·数据挖掘·单元测试·语音识别
计算机魔术师1 小时前
OpenAI 评定 Astra 达到网络安全 Critical 能力阈值,将受限发布
前端
JavaGuide1 小时前
SpaceX 工程师的 AI Coding 玩法太牛了, 200 多个 Agent 并行!
前端·后端
小猪code1 小时前
frp 80/443 Web 服务两种部署模式实操笔记
前端·笔记
JamesZhang800781 小时前
Chrome相关知识点
前端
jayson.h2 小时前
python——pdf编辑
前端·python·pdf
顶级自由人2 小时前
本地正常、线上正常,为什么一个 Hook 仍会报错?
前端·javascript·程序员
Android小行家2 小时前
Android APK 加固原理(五):SO `.text` 段加密、ELF 加载与运行时动态解密
前端
lerhxx2 小时前
R3F 第一人称漫游与碰撞检测:Pointer Lock + 不穿墙的滑墙秘诀(中)
前端·javascript·three.js