【TypeScript】类型兼容性与相关类型讲解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

类型兼容性

对象类型兼容性

接口类型兼容性

函数类型兼容性

索引签名类型

映射类型

索引查询类型

交叉类型


类型兼容性

在TS中类型采用的是结构化类型系统也叫做 duck typing鸭子类型类型检查关注的是值所具有的形状。也就是说在结构化系统中如果两个对象具有相同形状则认为他们属于同一类型。

class obj {x: number; y: number}
class obj1 {x: number; y: number}
// 因为TS的结构化类型只检查obj与obj1的结构是否相同
const p: obj = new obj1()

注意如果在 Nominal Type System中(比如C#、java等)它们是不同的类类型无法兼容。

对象类型兼容性

在结构化系统中如果两个对象具有相同的形状则认为他们属于同一类型。这种条件成立的前提在于成员多的可以赋予成员少的反之则报错。如下

class obj {x: number; y: number}
class obj1 {x: number; y: number; z: number}

// 成员多的 obj1 可以赋值给成员少的 obj
const p: obj = new obj1()

// const p1: obj1 = new obj() 成员少不能赋值给成员多的报错

接口类型兼容性

接口类型兼容性类似于class。并且class和interface之间也可以兼容。

interface person {
  name: string
  age: number
}
interface person1 {
  name: string
  age: number
}
interface person2 {
  name: string
  age: number
  say: ()=> void
}
let p1: person = {name:'张三',age:18}
let p2: person1 = {name:'李四',age:17}
let p3: person2 = {name:'王五',age:16,say(){}}
p2=p1
p1=p2
// p3=p1 报错

// 类和接口之间也可以兼容
class person3 {
  name: string
  age: number
  say: ()=> void
}
let p4: person3 = {name:'陈六',age:15,say(){}}
p2=p4

函数类型兼容性

函数类型的兼容性比较复杂需要考虑以下三种情况

参数个数参数多的兼容参数少的即参数少的可以赋值给参数多的。

type F1 = (a: number) => void
type F2 = (a: number,b: number) => void
let f1: F1 = (a=1)=>{}
let f2: F2
f2=f1
// f1=f2 参数多的不能赋值给参数少的 报错

参数类型相同位置的参数类型要相同原始类型或兼容对象类型。

type F1 = (a: number) => void
type F2 = (a: number) => void
let f1: F1 = ()=>{}
let f2: F2 = ()=>{}
f1 = f2

在对象类型中参数可能很多这个时候就需要参数多的兼容参数少的即参数少的能赋值给参数多的如下

interface point1 {
  name:string
  age:number
}
interface point2 {
  name:string
  age:number
  say():void
}
type F1 = (P:point1) => void // 相当于两个参数
type F2 = (P:point2) => void // 相当于三个参数

let f1:F1=()=>{}
let f2:F2
f2=f1

返回值类型只关注返回值类型本身即可。如果返回值类型是原始类型类型之间要相同如果返回值类型是对象类型成员多的可以赋值给成员少的。

// 原始类型
type F1 = ()=> string
type F2 = ()=> string
let f1: F1 = ()=>{return '1'}
let f2: F2 = f1

// 对象类型
type F3 = {name:string}
type F4 = {name:string,age:number}
let f3: F3
let f4: F4 = {name:'张三',age:18}
f3=f4

索引签名类型

绝大部分情况下我们可以在使用对象前就确定对象的结构并为对象添加准确的类型。然而当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性)此时就需要用到索引签名类型。

interface anyObj {
  // 使用 [key: string] 来约束该接口允许出现的属性名称。
  // key只是一个占位符可以换成任意合法的名称
  [key: string]: number
}
let obj: anyObj = {
  // 表示只要是string类型都可以出现在对象中这样对象就可以出现任意多个字符
  a:1,
  abc:12,
  xzx:1
}

在JS中数组是一类特殊的对象特殊在数组的键也就是索引是数组类型并且数组也可以出现任意多个元素。所以在数组对应的泛型接口中也用到了索引签名类型。

interface MyArr<type>{
  [index: number]: type
}
// 符合数组索引必须是 number 这一类型。
let arr: MyArr<number> = [1,2,3]
arr[0]

映射类型

映射类型是基于旧类型创建新类型对象类型减少重复、提升开发效率。映射类型是基于索引签名类型的所以该语法类似于索引签名类型也使用了 [] 。

注意映射类型只能在类型别名中使用不能在接口中使用。

// 普通写法每次写一个变量就要再一次声明其类型
type Type1 = {x:number;y:number;z:number}
// 映射写法创建对象的新类型与声明的类型结构完全一致。
type PropKeys = 'x'|'y'|'z'
type Type2 = {[keys in PropKeys]: number}

映射类型除了上文的联合类型创建新类型外还可以根据对象类型来创建

type props = {a: number;b: string;c: boolean}
// keyof表示键名是props中所有键名的任意一个。
// 这种方式类似将许多类型统一为同一个类型。
type Type = {[key in keyof props]: number}

索引查询类型

索引查询类型作用是用来查询属性的类型。注意[]中的属性必须存在于被查询类型中否则会报错。如下

type props = {a: number;b: string;c: boolean} 
// 查询单个索引类型
type Type = props['a']
// 查询多个索引类型
type Type1 = props['a'|'b']
// 查询所有索引类型
type Type2 = props[keyof props]

交叉类型

交叉类型&功能类似于接口继承extends用于组合多个类型为一个类型常用于对象类型使用教程类型后新的类型就具备被交叉的类型的所有属性类型。如下

interface Cat {
  name:string
}
interface Dog {
  say():void
}
// Animals属性同时具备 接口 Cat和Dog 的所有属性
type Animals = Cat & Dog
let p: Animals = {
  name:'毛',
  say(){
    console.log('汪汪');
  }
}

交叉类型&与 接口继承extends的对比

相同点都可以实现对象类型的组合。

不同点两种方式实现类型组合时对于同名属性之间处理类型冲突的方式不同。

当不同的接口类型出现同名属性不兼容的时候接口继承处理的方法是报错

 interface Cat {
  fn:(value:number)=>string
 }
 interface Dog extends Cat {
  fn:(value:string)=>string
 }

当不同的接口类型出现同名属性不兼容的时候交叉类型处理的方法是处理成联合类型

interface Cat {
fn:(value:number)=>string
}
interface Dog {
fn:(value:string)=>string
}
type Animals = Cat & Dog
// 交叉类型将fn的参数值类型变为联合类型  fn:(value:number|string) => string
// ! 作用强调这个值不为空
let p!: Animals
// 没有报错
p.fn(1) 
p.fn('2')
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6