Typescript类,泛型,各种类型工具
admin
2024-01-21 01:50:46
0

一、TypeScript 类

一个类可以包含以下几个模块:

  • 1.属性
    • 1.1 类属性
    • 1.2 实例属性
  • 2.构造函数(在python中叫初始化函数)
    该函数在类实例化时会被立即调用
  • 3.方法(也是函数,不过不用写 关键字function的函数)

1.1 类的属性与方法

官网:
传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的。 ES6 开始JavaScript程序员将能够使用基于类的面向对象的方式。 使用TypeScript,我们允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript版本。

在 TypeScript 中,我们可以通过 Class 关键字来定义一个类:

class Greeter {static cname: string = "Greeter";greeting: string;constructor(message: string) {this.greeting = message;}static getClassName() {return "Class name is Greeter";}greet() {return "Hello, " + this.greeting;}
}
let greeter = new Greeter("world");

那么成员属性与静态属性,成员方法与静态方法有什么区别呢?这里无需过多解释,我们直接看一下编译生成的 ES5 代码:

"use strict";
var Greeter =  (function () {function Greeter(message) {this.greeting = message;}Greeter.getClassName = function () {return "Class name is Greeter";};Greeter.prototype.greet = function () {return "Hello, " + this.greeting;};Greeter.cname = "Greeter";return Greeter;
}());
var greeter = new Greeter("world");

1.2 私有字段

在 TypeScript 3.8 版本就开始支持 ECMAScript 私有字段,使用方式如下:

class Person {#name: string;constructor(name: string) {this.#name = name;}greet() {console.log(`Hello, my name is ${this.#name}!`);}
}let semlinker = new Person("Semlinker");semlinker.#name;

与常规属性(甚至使用 private 修饰符声明的属性)不同,私有字段要牢记以下规则:

  • 私有字段以 # 字符开头,有时我们称之为私有名称;
  • 每个私有字段名称都唯一地限定于其包含的类;
  • 不能在私有字段上使用 TypeScript 可访问性修饰符(如 public 或 private);
  • 私有字段不能在包含的类之外访问,甚至不能被检测到。

1.3 get 和 set 关键字

面向对象的封装性要求中,常需要我们对类的一些属性进行封装,避免外部直接操作属性,经常使用两个方法进行处理,Getter 方法用于获取属性的值,Setter 方法用户设置属性的值。在 Ts 中可以使用 get 和 set 关键字来定义这两个方法

class Student{private _name;constructor(name: string){this._name = name;}get name(){return this._name;}set name(name: string){this._name = name;}
}// 此时实例对象我们可以这样对name属性进行处理
let obj = new Student("chen")
obj.name = "zhang"

1.4 类的继承

继承(Inheritance)是一种联结类与类的层次模型。指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系。

在 TypeScript 中,我们可以通过 extends 关键字来实现继承:

class Animal {name: string;constructor(theName: string) {this.name = theName;}move(Meters: number = 0) {console.log(`${this.name} moved ${Meters}m.`);}
}
class dog extends Animal {constructor(name: string) {super(name); }move(Meters = 5) { super.move(Meters);}
}let sam = new dog("dog");
sam.move();

1.5 抽象类

使用 abstract 关键字声明的类,我们称之为抽象类。抽象类不能被实例化,因为它里面包含一个或多个抽象方法。所谓的抽象方法,是指不包含具体实现的方法:

abstract class Person {constructor(public name: string){}abstract say(words: string) :void;
}const lolo = new Person(); //无法创建抽象类的实例

抽象类不能被直接实例化,我们只能实例化实现了所有抽象方法的子类。简单理解可以将它理解为一个模板类,其中可以定义一些未实现的方法,然后通过继承让其子类来实现这个 方法。具体如下所示:

abstract class Person {constructor(public name: string) {}abstract say(words: string): void;
}class Developer extends Person {constructor(name: string) {super(name);}say(words: string): void {console.log(`${this.name} says ${words}`);}
}

1.6 类方法重载

在前面的章节,我们已经介绍了函数重载。对于类的方法来说,它也支持重载。比如,在以下示例中我们重载了 ProductService 类的 getProducts 成员方法:

class ProductService {getProducts(): void;getProducts(id: number): void;getProducts(id?: number) {if(typeof id === 'number') {console.log(`获取id为 ${id} 的产品信息`);} else {console.log(`获取所有的产品信息`);}  }
}const productService = new ProductService();
productService.getProducts(666); 
productService.getProducts();

1.7 static

当类 中 的 方法 被 声明 为 static 时,其实例化 对象 不可 调用 该方法,只有 类 本身 ,以及 其子类 可以 调用。

class A {name:string;age:number;constructor(name:string,age:number){this.name = name;this.age = age;}eat(){console.log('测试');}static eat2(){console.log('测试2');}
}
let a = new A('zhangsan',8);
a.eat();//   '测试'
a.eat2();// error class B extends A {constructor(name:string,age:number){super(name,age);}
}
let  b = new B('lisi',9);
b.eat();// '测试'
b.eat2();// error
B.eat2();// '测试2' 

二、TypeScript 泛型

软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
泛型(Generics)是允许同一个函数接受不同类型参数的一种模板。相比于使用 any 类型,使用泛型来创建可复用的组件要更好,因为泛型会保留参数类型。

2.1 泛型语法

对于刚接触 TypeScript 泛型的读者来说,首次看到 语法会感到陌生。其实它没有什么特别,就像传递参数一样,我们传递了我们想要用于特定函数调用的类型。

参考上面的图片,当我们调用 identity(1)Number 类型就像参数 1 一样,它将在出现 T 的任何位置填充该类型。图中 内部的 T 被称为类型变量,它是我们希望传递给 identity 函数的类型占位符,同时它被分配给 value 参数用来代替它的类型:此时 T 充当的是类型,而不是特定的 Number 类型。

其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替。除了 T 之外,以下是常见泛型变量代表的意思:

  • K(Key):表示对象中的键类型;
  • V(Value):表示对象中的值类型;
  • E(Element):表示元素类型。

其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。比如我们引入一个新的类型变量 U,用于扩展我们定义的 identity 函数:

function identity (value: T, message: U) : T {console.log(message);return value;
}console.log(identity(68, "Semlinker"));

除了为类型变量显式设定值之外,一种更常见的做法是使编译器自动选择这些类型,从而使代码更简洁。我们可以完全省略尖括号,比如:

function identity (value: T, message: U) : T {console.log(message);return value;
}console.log(identity(68, "Semlinker"));

在使用泛型的时候 类型推论显得尤为重要

2.2 泛型接口

interface GenericIdentityFn {(arg: T): T;
}

2.3 泛型类

class GenericNumber {zeroValue: T;add: (x: T, y: T) => T;
}let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {return x + y;
};

2.4 泛型工具类型(很重要)

1.typeof

在 TypeScript 中,typeof 操作符可以用来获取一个变量声明或对象的类型。

interface Person {name: string;age: number;
}const sem: Person = { name: 'semlinker', age: 33 };
type Sem= typeof sem; function toArray(x: number): Array {return [x];
}type Func = typeof toArray;
2.keyof

keyof 操作符是在 TypeScript 2.1 版本引入的,该操作符可以用于获取某种类型的所有键,其返回类型是联合类型。

type Point = { x: number; y: number };
type P = keyof Point;
// type P = "x" | "y"type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish;
// type A = numbertype Mapish = { [k: string]: boolean };
type M = keyof Mapish;
// type M = string | number 
//注意 JavaScript 对象的属性名会被强制转为一个字符串
3.in

in 用来遍历枚举类型: 注意不能用于interface

type Keys = "a" | "b" | "c"type Obj =  {[p in Keys]: any
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nik1Y1lD-1668506733098)(2022-11-02-18-00-39.png)]

4.infer

在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用。

type ListType = V extends { list?: infer K } ? K : V

以上代码中 infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用。 上述简单来说K 接收 list的返回类型 如果V中有可选list 那么V的类型就是K 也就是list 否则V的类型是它本身

5.extends

有时候我们定义的泛型不想过于灵活或者说想继承某些类等,可以通过 extends 关键字添加泛型约束。

interface Lengthwise {length: number;
}function loggingIdentity(arg: T): T {console.log(arg.length);return arg;
}

现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:

loggingIdentity(3);

这时我们需要传入符合约束类型的值,必须包含必须的属性:

loggingIdentity({length: 10, value: 3});
6 Partial

Partial 的作用就是将某个类型里的属性全部变为可选项 ?

定义:

type Partial = {[P in keyof T]?: T[P];
};

在以上代码中,首先通过 keyof T 拿到 T 的所有属性名,然后使用 in 进行遍历,将值赋给 P,最后通过 T[P] 取得相应的属性值。中间的 ? 号,用于将所有属性变为可选。

示例:

interface Todo {key: string;value: string;
}
//使用Partial的情况就变成了
Partial 
//相当于 
interface Todo {key?: string;value?: string;
}
7 Readonly

用来构造一个类型,将Type的所有属性都设置为readonly(只读) 无法修改

interface Props {id: string 
} 
type Type= Readonly
let a={id:1
}
a.id=3  //ERROR 
8 Pick

从Type中选择一组属性来构造新类型

interface Props {id: stringtitle: stringchildren: number[]
}type PickProps = Pick

1 Pick工具类型有两个类型变量:1、表示选择谁的属性 2、表示选择哪几个属性。
2 其中第二个类型变量,如果只选择一个则只传入该属性名即可。
3 第二个类型变量传入的属性只能是第一个类型变量中存在的属性。
4 构造出来的新类型PickProps,只有id和title两个属性类型。

9 Record

构造一个对象类型,属性键为Keys,属性类型为Type。

export default interface CurrentUser {/** 权限对象 */roles: Record
}
// .roles 对象可以字符串为keys  但是值必须是boolean类型

ring
children: number[]
}

type PickProps = Pick

> 1 Pick工具类型有两个类型变量:1、表示选择谁的属性 2、表示选择哪几个属性。
> 2 其中第二个类型变量,如果只选择一个则只传入该属性名即可。
> 3 第二个类型变量传入的属性只能是第一个类型变量中存在的属性。
> 4 构造出来的新类型PickProps,只有id和title两个属性类型。##### 9  Record
构造一个对象类型,属性键为Keys,属性类型为Type。
```typescript
export default interface CurrentUser {/** 权限对象 */roles: Record
}
// .roles 对象可以字符串为keys  但是值必须是boolean类型

相关内容

热门资讯

自动打开应用安卓系统,安卓系统... 你有没有想过,手机里的那些应用,有时候真是让人又爱又恨呢?有时候,我们急需某个应用,却得费老大力气去...
安卓系统防沉迷软件,守护青少年... 你有没有发现,现在手机上玩游戏的诱惑力简直让人无法抗拒?尤其是安卓系统,那丰富的游戏资源,简直让人停...
流量最快的安卓系统,揭秘流量最... 你有没有想过,为什么你的手机总是那么卡,而别人的手机却像开了挂一样流畅?是不是好奇,为什么有些安卓系...
小米5换换安卓系统,畅享极致性... 你有没有想过,你的小米5手机,那个陪伴你走过无数日夜的小家伙,是不是也该给它来个“换新装”了呢?没错...
国产的安卓系统手机,畅享智能生... 你有没有发现,最近国产的安卓系统手机越来越火了?没错,就是那种咱们自己研发的系统,那种让外国品牌都不...
安卓系统刷入停止,探究原因与解... 你有没有遇到过这种情况?手机刷机过程中突然停止了,安卓系统刷入停滞不前,心里那个急啊!别慌,今天就来...
汽车是安卓系统嘛,安卓系统在智... 你有没有想过,汽车里那个神奇的操作系统,是不是和安卓手机里的一样呢?没错,今天咱们就来聊聊这个话题—...
网易狼人杀 安卓系统,体验指尖... 亲爱的玩家们,你是否曾在深夜里,手机屏幕前,与一群好友展开一场惊心动魄的“狼人杀”对决?今天,就让我...
小米安卓系统小主机,探索小米安... 你有没有想过,家里的电视、电脑、平板,甚至手机,其实都可以变成一个超级智能的娱乐中心?没错,这就是小...
卡刷安卓系统大全,全面解析各类... 你有没有想过,你的安卓手机可以像变形金刚一样,随心所欲地变换模样?没错,今天就要给你揭秘一个神奇的世...
安卓系统测试流畅度,安卓系统流... 你有没有发现,现在手机更新换代的速度简直就像坐上了火箭呢!尤其是安卓系统,每次更新都让人眼前一亮。但...
安卓系统50怎么升级,轻松迈向... 亲爱的安卓用户们,你是否也像我一样,对安卓系统的更新充满了期待?没错,就是那个让我们的手机焕然一新的...
安卓5.1.1操作系统,系统特... 你知道吗?在手机世界里,操作系统就像是个大管家,它不仅决定了手机的脸面,还掌管着手机的所有“家务事”...
手机安卓系统如果升级,体验流畅... 亲爱的手机控们,你们有没有发现,你的安卓手机最近是不是总在提醒你更新系统呢?别急,别急,今天就来给你...
安卓系统怎么禁止待机,安卓系统... 手机待机时间短,是不是让你头疼不已?别急,今天就来教你一招,让你的安卓手机告别“短命”模式,延长待机...
亿联安卓苹果系统,跨平台沟通新... 你知道吗?在科技飞速发展的今天,手机操作系统可是咱们日常生活中不可或缺的一部分。说起手机系统,亿联安...
smoothx安卓系统安装ap... 你有没有想过,为什么你的手机里总是乱糟糟的,各种app堆在一起,找起来费劲得很?别急,今天就来教你怎...
安卓系统图库在哪里,图库应用位... 你有没有发现,手机里的照片越来越多,有时候想找一张特定的照片,却像大海捞针一样困难?别急,今天就来告...
安卓7.0系统自带彩蛋,隐藏彩... 你知道吗?安卓7.0系统里竟然藏着不少小秘密,就像一颗颗隐藏的彩蛋,等着我们去发现。今天,就让我带你...
安卓系统好用的电池,好用到飞起... 你有没有发现,用安卓手机的时候,电池续航能力简直让人爱不释手啊!没错,今天咱们就来聊聊这个话题——安...