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

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 【TypeScript】类型兼容性与相关类型讲解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

目录

类型兼容性

对象类型兼容性

接口类型兼容性

函数类型兼容性

索引签名类型

映射类型

索引查询类型

交叉类型


类型兼容性

在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}

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

索引查询类型

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

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
 }

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

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

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')

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/140020.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!