TypeScript学习笔记之二(高级类型)

文章目录

  • 一、TypeScript高级类型
    • 1.1 class类
    • 1.2 class继承
    • 1.3 class类成员可见性
    • 1.4 readonly
    • 1.5 类型兼容性
      • 1.5.1 对象之间的类型兼容性
      • 1.5.2 接口之间类型兼容性
      • 1.5.3 函数之间类型兼容性
    • 1.6 交叉类型
    • 1.7 交叉类型(&)和继承(extends)的对比
  • 二、泛型
    • 2.1 泛型约束--指定更具体的类型
    • 2.2 泛型约束--extends添加约束
    • 2.3 多个泛型变量
    • 2.4 泛型接口
    • 2.5 泛型类
    • 2.6 泛型工具类Parital\<Type\>
    • 2.7 泛型工具类Readonly\<Type>
    • 2.8 泛型工具类Pick\<Type, Keys>
    • 2.9 泛型工具类Record\<Keys, Type>
  • 三、索引签名类型
  • 四、映射类型


一、TypeScript高级类型

1.1 class类

TypeScrtip全面支持ES2015中引入的class关键字,并为其添加了类型注解和其他语句
class基本使用
TS中的class,不仅提供了class的语法功能,也作为一种类型存在

class Person {}
const p:Person = new Person()

实例属性初始化

class Person {
  name: string = "kangyun";
  gender = "男";
}
const p: Person = new Person();

构造函数
构造函数:为class类的实例属性初始化值的
构造函数不需要返回值

class Person {
  name: string;
  gender: string;
  constructor(name: string, gender: string) {
    this.name = name;
    this.gender = gender;
  }
}
const p: Person = new Person('张三', '男');
</script>

类的实例方法

class Person {
  name: string;
  gender: string;
  constructor(name: string, gender: string) {
    this.name = name;
    this.gender = gender;
  }
  // 方法的类型注解(参数和返回值)与函数用法相同
  sayHello(name: string): void {
    console.log(`hello,${name}`);
  }
}
const p: Person = new Person("张三", "男");
p.sayHello("李四");

1.2 class继承

类继承的两种方式:

  • extends(继承父类)
  • implements(实现接口)

JS中只有extends,而implements是TS提供的

class Animail {
  move() {
    console.log("Moving!");
  }
}

class Dog extends Animail {
  bark() {
    console.log("汪汪......");
  }
}
// 子类Dog继承父类Animal,则Dog的实例对象dog就同时具有了父类
// Animal和子类Dog的所有属性和方法
const dog: Dog = new Dog();
dog.move();
dog.bark();
interface Singable {
  name: string;
  sing: () => void;
}
// Person类实现接口Singable就必须提供Singble接口中指定的方法和属性
class Person implements Singable {
  name = "张三";
  sing() {
    console.log("开始黄牛叫了......");
  }
}

1.3 class类成员可见性

可见性修饰符包括:

  • public 公有的
  • proected 受保护的
  • private 私有的

public表示公共、公有的,公有成员可以被任何地方访问
public: 是默认可见性,所以可以直接少略

class Animal{
  public move(){
    console.log('moving!')
  }
}

protected: 表示受保护的,仅对其所在类和子类中(非实例对象)可见
在子类的方法内部可以通过this来访问父类中受保护的成员,但是对实例不可见

class Animal {
  protected move() {
    console.log("moving");
  }
}
class Dog extends Animal {
  bark() {
    console.log("汪汪......");
    this.move();
  }
}
const dog = new Dog();
dog.bark();

在这里插入图片描述
private: 表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的

class Animal {
  private move() {
    console.log("moving");
  }
  walk(){
    this.move()
  }
}

1.4 readonly

readonly表示只读,用来防止在构造函数之外对属性进行赋值

class Animal {
  readonly age: number;
  constructor(age: number) {
    this.age = age;
  }
}
  • readonly只能修饰属性不能修饰方法
  • 接口或者{}表示的对象类型,也可以使用readonly修饰

1.5 类型兼容性

两种类型系统

  • Structural Type System(结构化类型系统)
  • Nominal Type System(标明类型系统)
    TS采用的是结构化类型系统,类型检查关注的是值所具有的形状
    在结构类型系统中如果两个对象具有相同的形状态,则认为它们属性同一类型
class Point01{x: number, y: number}
class Point02{x: number, y: number}
const p:Poing01 = new Point02()

因为TS是结构化类型系统,只检查Point01和Point02的结构是否相同(相同,都具有x和y两个属性,属性类型也相同)
但是如果在标明类型系统(如c#和java中)它们是不同的类,类型无法兼容。

1.5.1 对象之间的类型兼容性

对于对象类型来说,y的成员至少与x相同,则x兼容y(成员多的可以赋值给少的)

class Point {x: number; y: number}
class Point3D {x: number; y:number: z:number}
const p:Point = new Point3D()

1.5.2 接口之间类型兼容性

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

interface Point {x:number; y:number}
interface Point2D {x:number; y:number}
let p1: Point
let p2: Point2D = p1
interface Point3D {x:number; y:number; z:number}
let p3:Point3D
p2 = p3

1.5.3 函数之间类型兼容性

函数之间兼容性比较复杂,需要考虑参数个数、参数类型、返回值类型
参数个数,参数多的兼容参数少的(或者说参数少的可以赋值给多的)

type F1 = (a:number)=>void
type F2 = (a:number, b:number) => void
let f1: F1
let f2: F2 = F1
  • 参数少的可以赋值给参数多的,所以f1可以赋值给f2
  • 数组forEach方法的第一个参数是回调函数,该示例中类型为(value: string, index: number, array: string[])=>void
  • 在JS中省略用不到的函数参数实际是很常见的,这样的使用方式,促成了TS中函数类型之间的兼容性
  • 并且因为回调函数是有类型的,所以TS会自动推导出参数item、index、array的类型

***参数类型,***相同位置的参数类型要相同

type F1 = (a:number) => string
type F2 = (a:number) => string
let f1: F1
let f2: F2 = F1

函数类型F2兼容函数类型F1,因为F1和F2的第一个参数类型相同。

interface P2D {x:number; y:number}
interface P3D {x:number; y:number; z:number}
type F2 = (p:P2D)=>void
type F3 = (p:P3D)=>void
left f2: F2
let  f3: F3 = f2

技巧:将对象拆开,把每个属性看做一个一个的参数,则参数少的f2可以赋值给参数多的f3。

返回值类型,只关注返回值类型本身即可

type F5 = () => string
type F6 = () => string
let f5: F5
let f6: F6 = f5
type F7 = () => {name: string}
type F8 = () => {name: string, age: number}
let f7: F7
let f8: F8
// 返回的是对象,对象多的可以赋值给少的
f7 = f8

1.6 交叉类型

交叉类型(&):类似于接口继承,用于组合多个类型为一个类型(常用于对象类型)

interface Person {name: string}
interface Contact {phone: string}
type PersonDetail = Person & Contact
let obj: PersonDetail = {
    name: 'Bill',
    phone: '15220......'
}

使用交叉类型后,新的类型PersonDetail就同时具备了Person和Contact的所有属性类型,这和继承很相似。

1.7 交叉类型(&)和继承(extends)的对比

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

interface A {
    fn:(value: number) => string
}
interface B extends A {
    fn: (value: string) => string
}

上示代码接口继承会报错(类型不兼容)

interface A{
    fn:(value: number) => string
}
interface B{
    fn:(value: string) => string
)
type C = A & B
C的结果会是: fn:(value: number|string) => string

二、泛型

泛型是可以在保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用,常用于函数、接口、class中。
泛型是用来实现可复用组件功能的主要工具之一。

创建泛型函数

function id<Type>(value: Type):Type { return value}

PS:
在函数名称后面添加<>尖括号,尖括号中添加类型变量,如此处Type,类型变量Type,是一种特殊类型的变量,它处理类型而不是值。该类型变量相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)。因为Type是类型,因此可以将其作为函数参数和返回值的类型,类型变量Type,可以是任意合法的变量名称。

调用泛型函数

const num = id<number>(10)
const str = id<string>('hello')

PS:
当传入类型number后,这个类型就能会被函数声明时指定的类型变量Type捕获到。这样,通过泛型就做到了让id函数与多种不同的类型一起工作,实现了复用的同时保证了类型安全。

简化调用泛型函数

function id<Type>(value: Type):Type { return value}
let num01 = id<number>(10)
let num02 = id(10) //简化

简化由TS类型参数推断,当编译器无法推断类型或者推断的类型不准确时,就需要显式地传入类型参数。

2.1 泛型约束–指定更具体的类型

***泛型约束:***默认情况下,泛型函数的类型变量Type可以代表多个类型,这导致无法访问任何属性。
如:id(‘a’)调用函数时获取参数的长度

function id<Type>(value: Type): Type{
    console.log(value.length)
    return value
}

PS:
Type可以代表任意类型,无法保证一定存在length属性,如number就没有length,此时就需要为泛型添加约束来收缩类型
指定更具体的类型

function id<Type>(value: Type[]): Type[]{
    console.log(value.length)
    return value
}

将类型Type修改为Type[](Type类型的数组),因为只要是数组就一定存在Length。

2.2 泛型约束–extends添加约束

添加约束

interface ILength{ length: number }
function id<Type extends ILength>(value: Type): Type{
    console.log(value.length)
    return value
}

PS:
通过extends关键字使用该接口,为泛型(类型变量)添加约束,该约束表示:传入的类型必须具有length属性

2.3 多个泛型变量

泛型的类型变量可以有多个,并且类型变量之间还可以约束。

// Key extends keyof Type
// Key的值必须是Type类的key
function getProp<Type, Key extends keyof Type>(obj: Type, key: Key){
    reutnr obj[key]
}
let person = {name: 'kk', age: 18 }
getProp(person, 'name')

keyof关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型

2.4 泛型接口

泛型接口:接口也可以配合泛型来使用,以增加其灵活性,增强复用性

interface IdFunc<Type>{
    id: (value: Type) => Type
    ids: () => Type[]
}
let obj:IdFunc<number>{
    id(value){return value},
    ids(){ return [1, 2, 3] }

JS中的数组在TS中就是一个泛型接口

const strs = ['a', 'b', 'c']

在这里插入图片描述

2.5 泛型类

class GenericNumber<NumberType>{
    defaultValue: NumberType
    add: (x: NumberType, y: NumberType) => NumberType
}

PS:
类似于泛型接口,在class名称后添加<类型变量>这个类就成了泛型类,add方法采用的是箭头函数形式书写方式。

const myNum = new GenericNumber<number>()
myNum.defaultValue = 10

2.6 泛型工具类Parital<Type>

泛型工具类Parital<Type>用来构造(创建)一个类型,将Type的所有属性设置为可选。

interface Props {
    id: number,
    children: number[]
}
type ParitalProps = Parital<Props>

PS:构造出来的新类型ParitalProps结构和Props相同,但所有属性都变为可选的。

2.7 泛型工具类Readonly<Type>

泛型工具类Readonly<Type>用来构造一个类型,将Type的所有属性都设置为readonly(只读)

interface Props{
    id: string
    children: number[]
}
type ReadonlyProps = Readonly<Props>

解释:构造出来的新类型ReadonlyProps结构和Props相同,但所有属性都变为只读

let props: ReadonlyProps = {id: '1', children: [] }
props.id = '2' //error

重新给id属性赋值,会报错,因为它是只读属性。

2.8 泛型工具类Pick<Type, Keys>

泛型工具类Pick<Type, Keys>从Type中选择一组属性来构造新类型

interface Props{
    id: string
    title: string
    children: number
}
type PickProps = Pick<Props, 'id'|'title'>

Pick工具类型有两个类型变量:

  • 表示选择谁的属性
  • 表示要选择哪几个属性

构造出来的PickProps只有id和title两个属性类型。

2.9 泛型工具类Record<Keys, Type>

泛型工具类Record<Keys, Type>构造一个对象类型,属性键为Keys,属性类型为Type

type RecordObje = Record<'a'|'b'|'c', string[]>
let obj: RecordObje = {
    a: ['a'],
    b: ['2'],
    c: ['aaa]
}

PS:
Record工具类型有两个类型变量
1、表示对象有哪些属性
2、表示对象属性的类型

三、索引签名类型

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

interface AnyObject{
    [key: string]: number
}
let obj: AnyObject = {
    a: 1, 
    b: 2,
}

PS:
使用[key: string]来约束该接口中允许出现的属性名称。表示只要是string类型的属性名称,都要以出现在对象中。
key只是一个占位符,可以换成任意合法的变量名称。

四、映射类型

映射类型:基于旧类型创建新类型(对象类型)

type PropKeys = 'x' | 'y' | 'z'
type Type1 = { x:number; y: number; z: number }

上例有太多重复的代码

type PropKeys = 'x' | 'y' | 'z'
type Type2 = { [Key in PropKeys]: number}

映射类型是基于索引签名类型的,所以该语法类似于索引签名类型
映射类型只能在类型别名中使用,不能在接口中使用

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

type Props = {a: number; b: string; c: boolean}
type Type = { [key in keyof Props]: number }

PS:
先执行keyof Props获取到对象类型Props中所有键的联合类型即’a’|‘b’|‘c’
然后key in …就表示key可以是Props中所有的键名称中的任意一个

像泛型工具类型Parital<Type>这些都是基于映射类型实现的

type Parital<T> = {
    [P in keyof T]?: T[P]
}

T[p]在TS中叫做查询(访问)类型
用来查询属性的类型

type Props = {a: number; b: string; c: boolean}
type TypeA = Props['a'] // type TypeA = number

注意:[]中的属性必须存在于被查询类型中,否则就会报错。
索引查询类型的其他使用方式:同时查询多个索引的类型

type Props = {a: number; b: string; c: boolean}
type TypeA = Props['a'|'b']

使用字符串字面量的联合类型,获取属性a和b对应的类型结果为string|number

type TypeA = Props[keyof Props]

使用keyof操作符获取Props中所有键对应的类型,结果为number|string|boolean

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/7684.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

考虑大规模电动汽车接入电网的双层优化调度策略【IEEE33节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

蓝奥声核心技术分享——基于物联网的能源监测数据采集技术

1.技术背景 基于物联网的能源监测数据采集技术主要解决物联网能源监测节点面向目标对象以协同方式进行能源监测数据采集的问题&#xff0c;属于蓝奥声核心技术--边缘协同感知(EICS&#xff09;技术的关键支撑性技术之一。该项技术涉及无线物联网边缘智能与测控的技术领域&…

智能化生产,提高效率!使用关键词采集工具助力企业数字化转型

关键词采集工具在企业数字化转型中的优势和作用进行阐述。 随着信息技术的不断发展&#xff0c;企业数字化转型已经成为了企业发展的必然趋势。 对于各种规模的企业而言&#xff0c;数字化转型可以提升企业的生产效率、降低成本、提高产品质量等方面带来更多的发展机遇。 而关…

SpringBoot实战(十五)集成iText

目录1.简介2.Maven依赖3.实现示例&#xff1a;第1章1&#xff09;创建PDF文件&#xff0c;写入 Hello World2&#xff09;创建PDF&#xff0c;定制字体并写入多行&#xff08;Rick Astley 歌词&#xff09;3&#xff09;创建PDF&#xff0c;定制字体并写入文字和图片&#xff0…

【云原生etcd】etcd的快速入门

在云计算时代&#xff0c;如何让服务快速透明地接入到计算集群中&#xff0c;如何让共享配置信息快速被集群中的所有机器发现&#xff0c;更为重要的是&#xff0c;如何构建这样一套高可用、安全、易于部署以及响 应快速的服务集群&#xff0c;已经成为了迫切需要解决的问题。目…

兆芯最新X86 CPU曝光:性能与英特尔/AMD相比,没落后10年

众所周知&#xff0c;在PC领域&#xff0c;X86完全是处于垄断地全的&#xff0c;至少占了90%以上的份额。其它的像MIPS、ARM、RISC-V等等&#xff0c;都不是X86的对手。 这与X86是复杂指令集有关&#xff0c;更与X86绑定了windows操作系统&#xff0c;有坚固的intel联盟有关&am…

多模态模型学习1——CLIP对比学习 语言-图像预训练模型

多模态模型学习1——CLIP对比学习 语言-图像预训练模型学习前言什么是CLIP模型代码下载CLIP实现思路一、网络结构介绍1、Image Encodera、PatchPosition Embeddingb、Transformer EncoderI、Self-attention结构解析II、Self-attention的矩阵运算III、MultiHead多头注意力机制IV…

美国Embarcadero公司2023年2月27日正式发布RAD Studio Delphi 11.3

Embarcadero很高兴地宣布发布RAD Studio 11 Alexandria Release 3&#xff0c;也称为RAD Studio 11.3&#xff0c;以及Delphi 11.3和CBuilder 11.3。此版本侧重于质量和改进&#xff0c;以RAD Studio 11 Alexandria三个先前版本中的强大新功能为基础。 RAD Studio 11.3包括对多…

BUUCTF-[GWCTF 2019]babyvm

题目下载&#xff1a;下载 这种简单vm逆向搞了快半辈子了&#xff0c;看别人wp也看的迷迷糊糊的&#xff0c;今天突然就看明白了&#xff0c;可能是受一个python虚拟机题的影响&#xff0c;第一次见vm&#xff0c;简单记录一下~ 参考&#xff1a;系统学习vm虚拟机逆向_43v3rY…

标准分布的累计分布函数的差分去模拟离散的高斯分布

标准分布的累计分布函数的差分去模拟离散的高斯分布如何理解图像生成中“标准分布的累积分布函数的差分去模拟离散的高斯分布”&#xff1f;discretized_gaussian_log_likelihoodcodeapprox_standard_normal_cdftanh激活函数标准正态分布的累积密度函数如何理解图像生成中“标准…

提高代码质量!详解在Gradle项目中使用PMD的正确姿势

当今的软件开发需要使用许多不同的工具和技术来确保代码质量和稳定性。PMD是一个流行的静态代码分析工具&#xff0c;可以帮助开发者在编译代码之前发现潜在的问题。在本文中&#xff0c;我们将讨论如何在Gradle中使用PMD&#xff0c;并介绍一些最佳实践。 什么是PMD&#xff…

国内智慧城市标准是怎样的?

我国智慧城市标准化工作的历史可以回溯至2013 年&#xff0c;相关工作也得到了国家标准委、中央网信办、发展改革委、工业和信息化部等部门的高度关注和支持&#xff0c;在标准化协调机制、国家标准研制实施等方面取得了积极进展。 北京智汇云舟科技有限公司成立于2012年&#…

【vSphere | Python】vSphere Automation SDK for Python Ⅲ—— vCenter Datacenter APIs

目录5. vCenter Datacenter APIs操作5.1 Create Datacenter5.2 List Datacenter5.3 Get Datacenter5.4 Delete Datacenter参考资料5. vCenter Datacenter APIs 数据中心服务&#xff08;Datacenter service&#xff09;提供管理 vCenter Server 中数据中心的操作。 操作 Cre…

新加坡电商系统上线指南

如果您正在考虑在新加坡开展电子商务业务并准备上线您的电商网站&#xff0c;以下是一些指南和建议&#xff0c;可以帮助您成功地启动和运营您的电商业务&#xff1a; 确认您的业务模式和目标市场。在上线之前&#xff0c;您需要确定您的业务模式&#xff0c;例如是B2B&#xf…

Python 进阶指南(编程轻松进阶):六、编写 Python 风格的代码

原文&#xff1a;http://inventwithpython.com/beyond/chapter6.html 强大对于编程语言来说是一个没有意义的形容词。每种编程语言都称自己长处。官方 Python 教程开头就说 Python 是一种简单易学、功能强大的编程语言。但是没有一种语言可以做另一种语言不能做的算法&#xff…

Robosense激光雷达Linux配置

文章目录1.1 速腾rs16连接&#xff1a;1.2 网络配置1&#xff09;官方说明2&#xff09;设置网络3&#xff09;检查是否连接成功2.1 激光雷达ROS包下载/编译1)下载ROS包2&#xff09;安装libpcap依赖3&#xff09;修改编译模式4&#xff09;config文件配置5&#xff09;编译并运…

AI-TestOps —— 软件测试工程师的一把利剑

写在前面软件测试的前世今生测试工具开始盛行AI-TestOps 云平台● AI-TestOps 功能模块● AI-TestOps 自动化测试流程写在前面 最近偶然间看到一句话&#xff1a;“软件测试是整个 IT 行业中最差的岗位”。这顿时激起了我对软件测试领域的兴趣&#xff0c;虽然之前未涉及过软件…

《Flutter进阶》flutter升级空安全遇到的一些问题及解决思路

空安全出来挺久了&#xff0c;由于业务需求较紧&#xff0c;一直没时间去升级空安全&#xff0c;最近花了几天去升级&#xff0c;发现其实升级也挺简单的&#xff0c;不要恐惧&#xff0c;没有想象中的多BUG。 flutter版本从1.22.4升到3.0.5&#xff1b; compileSdkVersion从1…

日撸 Java 三百行day11-13

文章目录说明day11-day12 顺序表1.面向过程面向对象区别2.代码2.1 面向过程2.2 面向对象day13 链表1.成员内部类2.链表的插入删除3.代码说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了…

【51单片机】:LED任务及汇编解释任务

学习目标&#xff1a; 1、用汇编或者c语言实现D1 D3 D5 D7 为一组 &#xff1b;D2 D4 D6 D8 为一组 &#xff0c;两组实现 1&#xff09;一组亮约一秒 另一组灭一秒&#xff0c;这样的互闪现象五次后 25分 2&#xff09;所有灯灭约一秒后&#xff0c; …