TypeScript 中的 `&` 运算符:从入门、踩坑到最佳实践

一、& 的基本用法

交叉类型的概念非常直观:T & U 意味着一个值既是类型 T,又是类型 U。对于对象类型来说,就是将它们的属性合并。

来看一个最简单的例子:

typescript 复制代码
interface HasName {
    name: string;
}

interface HasAge {
    age: number;
}

// 使用交叉类型 & 创建一个新类型 Person
type Person = HasName & HasAge;

const person: Person = {
    name: 'Alice',
    age: 30
}; // OK, person 对象同时拥有 name 和 age 属性

Person 类型现在要求它的实例必须同时满足 HasNameHasAge 的所有要求。& 在这里就像胶水一样,把两个接口"粘"在了一起。

这不仅仅限于两个类型,你可以随心所欲地"粘"更多:

typescript 复制代码
interface HasId {
    id: number;
}

type UserProfile = HasName & HasAge & HasId;

const user: UserProfile = {
    id: 1,
    name: 'Bob',
    age: 25
};

二、深入理解 & 的AND逻辑

2.1 原始类型的交叉 -> never

一个值不可能同时是 string number 。因此,它们的交叉类型就是 never------一个永远不可能存在值的类型。

typescript 复制代码
type Impossible = string & number; // 类型推断为 never

let impossibleValue: Impossible; 
impossibleValue = "hello"; // Error: 不能将类型""hello""分配给类型"never"

2.2 同名属性的交叉

  • 如果同名属性的类型相同,则合并后类型不变。

    typescript 复制代码
    interface A {
        prop: string;
    }
    interface B {
        prop: string;
    }
    type C = A & B; // C 的类型是 { prop: string; }
  • 如果同名属性的类型不同 ,则合并后的属性类型会是这两个类型的交叉类型

    typescript 复制代码
    interface X {
        id: string;
    }
    interface Y {
        id: number;
    }
    
    type Z = X & Y;
    // Z 的类型是 { id: string & number; }
    // 因为 string & number 是 never,所以 id 的类型是 never
    const z: Z = {
        id: (():never=>{ throw new Error('')})()/* 只能给id赋值never */
    }; 

    这意味着,Z 类型实际上是一个无法被创建的类型,因为你无法为 id 属性提供一个既是 string 又是 number 的值。

2.3 组合优于继承

交叉类型是实践"组合优于继承"设计原则的利器。把复杂的多重继承简化为创建一个个可复用的小类型,然后按需将它们组合起来。

typescript 复制代码
interface Loggable {
    log(message: string): void;
}

interface Serializable {
    serialize(): string;
}

// 我们可以轻松创建一个既能打日志又能序列化的对象类型
type LoggableAndSerializable = Loggable & Serializable;

class MyObject implements LoggableAndSerializable {
    log(message: string) {
        console.log(message);
    }
    serialize() {
        return JSON.stringify(this);
    }
}

let obj = new MyObject();
obj.log('hello'); // 输出: hello
console.log(obj.serialize()); // 输出: {}

总结

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

相关推荐
小磊哥er28 分钟前
深入解构Claude Code - 第 3 篇 · 一问一答怎么转起来
javascript·ai编程
小磊哥er41 分钟前
深入解构Claude Code - 第 2 篇 · 启动的秘密
javascript·ai编程
雪芽蓝域zzs1 小时前
第八节:Element Plus 基础、封装通用组件 + 路由守卫
前端·vue.js
码视野1 小时前
基于 Spring Boot + Vue3 的【智慧公厕微负压排风除臭与客流人感空间占用导引中台】设计与实现(含PRD/三端高保真源码/大屏)
前端·vue.js·人工智能·spring boot·后端
计算机魔术师1 小时前
刚赔了15亿又来被告?索尼华纳联手把Anthropic告上法庭
前端
笑霸final1 小时前
不用上传服务器!用 Vue3 + ONNX Runtime Web 在浏览器本地实现智能抠图
运维·前端·图像处理·ai·onnx·canva可画·web性能优化
月月大王的3D日记1 小时前
Three.js 入门系列(9):从零搭一座“闹鬼小屋”
前端·javascript
TingTing2 小时前
Vue3动态组件库建设
前端
码上暴富2 小时前
Cursor / VS Code 自定义文件颜色
前端·vscode
开开心心就好2 小时前
电子教鞭工具支持画框写字插图片功能齐全
android·开发语言·前端·javascript·人工智能·pdf·html