TS中联合类型和交叉类型

联合类型

联合类型(Union Types)用于表示一个值可以是多个类型之一。使用竖线|将多个类型组合起来形成联合类型

变量联合类型

let x: string | number;
x = "hello"; 
// 合法

x = 123;    
// 合法

x = true;   
//  错误,不能将类型“boolean”分配给类型“string | number”。

函数参数联合类型

function printId(id: string | number) {
  console.log(id);
}

printId("abc"); 
// 输出:abc

printId(123);   
// 输出:123

printId(true);  
// 错误,类型“boolean”的参数不能赋给类型“string | number”的参数。

类型断言来处理联合类型

function getLength(strOrArr: string | number[]): number {
  if (typeof strOrArr === "string") {
    return strOrArr.length;
  } else {
    return strOrArr.length;
  }
}
console.log(getLength("hello"));       
// 输出:5

console.log(getLength([1, 2, 3, 4, 5])); 
// 输出:5

上面的代码看起来都很好理解,我们继续看下面的例子

对象联合类型

type A = {
  a: number;
  b: number;
};
type B = {
  b: number;
  c: number;
};
type C = A | B;
const c: C = {
  a: 1,
  b: 2,
  c: 3,
};
console.log(c.b); // 输出 2
console.log(c.a); 
// 错误 类型“C”上不存在属性“a”。类型“B”上不存在属性“a”。
console.log(c.c); 
// 错误 类型“C”上不存在属性“c”。类型“A”上不存在属性“c”。

const d: C = {
  a: 1,
  b: 2,
};
const e: C = {
  b: 1,
  c: 2,
};
const f: C = {
  a: 1,
};
/**
 * 错误 不能将类型“{ a: number; }”分配给类型“C”。
  类型 "{ a: number; }" 中缺少属性 "b",但类型 "A" 中需要该属性。ts(2322)
  1.ts(3, 3): 在此处声明了 "b"。
 */
const g: C = {
  c: 2,
};
/**
 * 不能将类型“{ c: number; }”分配给类型“C”。
 * 类型 "{ c: number; }" 中缺少属性 "b",但类型 "B" 中需要该属性。ts(2322)
 * 1.ts(6, 3): 在此处声明了 "b"。
 */
  • 上面的代码当我们定义c对象引用C类型时依次写出AB的所有属性,这时候并不会抛出异常,但当我们获取c.ac.c时抛出异常,这是因为在使用联合类型时,我们只能使用联合类型中所有类型共有的属性和方法。这样可以确保类型安全
  • 在联合类型中定义中,定义的值可以是多个类型中其中一个类型的成员,也可以时多个类型的成员
    • c的赋值 {a: 1, b: 2, c: 3} 包含了A类型的成员 a 和 b,以及B类型的成员 b 和 c,因此满足了C的定义,不会报错
    • d的赋值 {a: 1, b: 2} 包含了A类型的成员 a 和 b,没有C类型中定义的 c 成员,但是因为CAB的联合类型,所以满足了C的定义,不会报错
    • e的赋值 {b: 1, c: 2} 包含了B类型的成员 b 和 c,没有A类型中定义的 a 成员,但是因为CAB的联合类型,所以满足了C的定义,不会报错
    • f的赋值 {a: 1} 只包含了A类型的成员a,没有B类型中定义的成员 b 和 c,因此不满足C的定义,会报错
    • g的赋值 {c: 2} 只包含了B类型的成员 c,没有A类型中定义的成员 a 和 b,因此不满足C的定义,会报错

根据上述代码和解释说明,c、d、e、f、h 都是类型为C的变量。C类型是AB的联合类型,因此它可以是类型A的成员、类型B的成员,也可以是类型A和类型B类型的所有成员*

交叉类型

交叉类型(Intersection Types)允许我们将多个类型合并为一个新的类型。使用&符号将多个类型定义组合在一起形成交叉类型

合并接口的成员

interface Dog {
  woof(): void;
}

interface Cat {
  meow(): void;
}

type DogCat = Dog & Cat;

const animal: DogCat = {
  woof() {
    console.log("Woof");
  },
  meow() {
    console.log("Meow");
  },
};

animal.woof(); // 输出:Woof
animal.meow(); // 输出:Meow

合并对象的属性

const person = {
  name: "Alice",
  age: 30
};

const employee = {
  company: "ABC Inc.",
  salary: 5000
};

type PersonEmployee = typeof person & typeof employee;

const manager: PersonEmployee = {
  ...person,
  ...employee
};

console.log(manager.name);    // 输出:Alice
console.log(manager.age);     // 输出:30
console.log(manager.company); // 输出:ABC Inc.
console.log(manager.salary);  // 输出:5000

对象交叉类型

type A = {
  a: number;
  b: number;
};
type B = {
  b: number;
  c: number;
};
type C = A & B;
const c: C = {
  a: 1,
  b: 2,
  c: 3,
};
console.log(c.a); // 输出 2
console.log(c.b); // 输出 2
console.log(c.c); // 输出 3
const d: C = {
  a: 1,
  b: 2,
};
/**
 * 不能将类型“{ a: number; b: number; }”分配给类型“C”。
 * 类型 "{ a: number; b: number; }" 中缺少属性 "c",但类型 "B" 中需要该属性。ts(2322)
 * 1.ts(7, 3): 在此处声明了 "c"。
 */
const e: C = {
  b: 1,
  c: 2,
};
/**
 * 不能将类型“{ b: number; c: number; }”分配给类型“C”。
 * 类型 "{ b: number; c: number; }" 中缺少属性 "a",但类型 "A" 中需要该属性。ts(2322)
 * 1.ts(2, 3): 在此处声明了 "a"。
 */
const f: C = {
  a: 1,
};
/**
 * 不能将类型“{ a: number; }”分配给类型“C”。
 * 类型 "{ a: number; }" 中缺少属性 "b",但类型 "A" 中需要该属性。ts(2322)
 * 1.ts(3, 3): 在此处声明了 "b"。
 */
const g: C = {
  c: 2,
};
/**
 * 不能将类型“{ c: number; }”分配给类型“C”。
 * 类型“{ c: number; }”缺少类型“A”中的以下属性: a, bts(2322)
 */
  • 在联合类型中定义中,定义的值必须满足所有类型的成员
    • c的赋值 {a: 1, b: 2, c: 3} 包含了类型A中定义的 a 和 b 成员,以及类型B中定义的 b 和 c 成员。因此,它满足了类型C的定义,是一个有效的赋值
    • d的赋值 {a: 1, b: 2},它只包含了类型A中定义的 a 和 b 成员,没有包含类型B中定义的 c 成员。因此,它不满足类型C的定义,会报错
    • e的赋值 {b: 1, c: 2},它只包含了类型B中定义的 b 和 c 成员,没有包含类型A中定义的 a 成员。因此,它不满足类型C的定义,会报错
    • f的赋值 {a: 1},它只包含了类型A中定义的 a 成员,没有包含类型B中定义的 b 和 c 成员。因此,它不满足类型C的定义,会报错
    • g的赋值 {c: 2},它只包含了类型B中定义的 c 成员,没有包含类型A中定义的 a 和 b 成员。因此,它不满足类型C的定义,会报错

    根据上述代码和解释说明,c、d、e、f、h 都是类型为C的变量。C类型是AB的交叉类型,这意味着C类型的变量需要同时满足类型A和类型B的成员

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值