TS类和接口

TS像其他语言一样,也有类及接口的概念。扩展类时使用extends关键字,使用implements关键字指明该类满足某个接口。还可以有抽象类,一共有三种可见效:private、protected及public(默认)。

1 基础

子类可以扩大可见范围,但不能缩小范围(但是不能扩大private的范围)。子类的实例属性类型必须与父类保持一致。

class Person {constructor(protected name:string,private age:number) {}
}class Man extends Person {// age 为形参,父类的age因为是private,所以不能在子类中被定义constructor(public name:string,age: number) {super(name,age);}
}

子类只能把父类为protected的实例属性的可见效扩大为public。

1.1 以this为返回类型

this可以用作值,也能用作类型。

假如某个类有个实例方法,方法的返回值为其本身。如果将返回类型设置为这个类名,将会有两个问题:1)不能保证返回的是该类实例本身;2)如果该类被继承,则返回类型也要做相应的修改。 所以此时,将this作为返回类型将是最优解。

class List {protected array: any[] = [];add(item:any):this {this.array.push(item);return this;}showArray() {console.log(this.array);}
}class UniqueList extends List{add(item:any):this {let inHere = false;for (let it of this.array) {if (it === item) {inHere = true;break;}}if (!inHere) {this.array.push(item);}return this;}
}let list = new UniqueList();
list.add(1).add("hello").add(494).add("word").add(1).add(999).add("word");
list.showArray();

1.2 接口

与类型别名基本相似,但有细微的差别:

1)类型别名更为通用,右边可以是任何类型,而接口右边必须为结构。

2)扩展接口时,ts将检查扩展的接口是否可赋值给被扩展的接口,而类型不会。

3)同名接口自动合并,但类型别名不能相同。

type A = {val: numberfun1(arg:number,arg2: string):void
}// 报错,类型不能同名
// type A = {
//
// }// 类型合并不做检查
type B = A & {fun1(arg:string):void
}let b: B = {val: 20,fun1(arg: string | number,arg2?:string) {console.log("hello");}
}interface C {val: numberfun1(arg:number,arg2: string):void
}// 接口同名会被合并
interface C {fun2():void
}// 接口扩展时会检查是否安全
interface D extends C{
//    fun1(arg:string):void //error Type (arg: string) => void is not assignable to type (arg: number, arg2: string) => void
}class X implements C {val: number;constructor(num: number) {this.val = num;}fun1(arg: number, arg2: string): void {console.log('hello X')}fun2(): void {}
}let x = new X(999);
console.log(x); // X { val: 999 }

对于第二点,我们在做扩展时常会用接口形式,因为这样做更安全。

对于接口中readonly属性,在被类实现时readonly会失效,但是如果不被类实现而直接实例化,则readonly有效。

interface A {readonly val: number
}class X implements A {val = 1
}let x = new X();
console.log(x);
x.val = 23 // 仍然可写
console.log(x);let a: A = {val:23};
a.val = 99; // 报错:Cannot assign to val because it is a read-only property.

接口

接口更通用、更轻量、只存在于编译阶段。

抽象类

抽象类更具体、功能更丰富、生成运行时代码。

表 接口与抽象类的比较

2 进阶

类是结构化类型。TS根据结构比较类,与类的名称无关。类与其他类型是否兼容,要看结构。

class A {fun() {console.log("a");}
}
class B {fun() {console.log("b");}
}let a:A = new A();
let b:B = new B();
let c = a;
a = b;
b = c;
console.log(a); // B {}
console.log(b); // A {}
a.fun(); // b
b.fun(); // a

2.1 多态

类和接口与函数一样,对泛型参数也有深层支持,包括默认类型和限制。

type ValueType<V> = {[key:string]:V
}class CustomMap<V> {private readonly value: ValueType<V>constructor(key:string,val: V) {this.value = {};this.value[key] = val;}put(key:string,val:V) {this.value[key] = val;}get(key:string):V{return this.value[key];}// 静态方法不能访问类型的范型static fun<K>(arg:K) {}
}
// 可以显式绑定具体类型也可以让TS自动推导
let map = new CustomMap("one","val1");
map.put("two","val2");
console.log(map.get("two")); // val2
console.log(map.get("three")) // undefined

2.2 类既声明值也声明类型

在ts中,多数时候,表达的要么是值要么是类型:

值:

let a=99; function fub() {};

类型:

type a = number;

interface B {}

类和枚举比较特殊,它们既可以表示类型也可以表示值。

class C{}

let c:C // 指C的实例类型

= new C(); // 指值C

一个类由静态类型(构造函数+静态方法及静态属性)与实例类型(实例属性及实例方法)组成。

class C {static readonly CLASS_NAME:string = "C";id:number=0;constructor() {}fun() {}static staticFun() {}
}interface InstanceC{ // C的实例类型id:numberfun():void
}interface StaticC { // C的静态类型readonly CLASS_NAME:stringnew(): CstaticFun():void
}let c = new C();
let instanceC:InstanceC;
let staticC:StaticC;instanceC = c;
// staticC = c; // 报错 Type C is missing the following properties from type StaticC: CLASS_NAME, staticFun
// instanceC = C; // 报错 Type typeof C is missing the following properties from type InstanceC: id, fun
staticC = C;// 实例不能访问静态
// c.CLASS_NAME; //报错 Property CLASS_NAME does not exist on type C
console.log(staticC.CLASS_NAME); // C

2.3 混入mixin

Vue中的混入是指将多个相同的逻辑抽离出来,各个组件只需引入mixins,就可以在各个组件使用这些逻辑。

JS和TS都没有mixin关键字,不过我们可以自己实现混入。

需求:要求每个组件打印其实例属性(public 可见性)JSON格式。

type ClassConstructor = new(...args:any[]) => {}function createMixinModule<C extends ClassConstructor>(Class:C) {return class extends Class {showFieldJson() {let str = Class.name + "("for (let key in this) {str += key + ":" + this[key] + ";"}str += ")";console.log(str);}}
}class ModuleA {constructor(public name: string, public val:number) {}
}class ModuleB {constructor(public type: number,public color: string) {}
}let A = createMixinModule(ModuleA);
let B = createMixinModule(ModuleB);
let a = new A("moduleA", 999);
let b = new B(-1,"red");
a.showFieldJson(); // ModuleA(name:moduleA;val:999;)
b.showFieldJson(); // ModuleB(type:-1;color:red;)

3 TS与设计模式

“不自己动手实现一两个设计模式怎么算得上是讨论面向对象编程呢?”

3.1 装饰模式

需求:对每一个发出的请求,都打印出请求path、方法及参数。

type ClassConstruct<T> = new(...args:any[]) => Tfunction createDecoratorRequest<C extends ClassConstruct<{request(path:string,method:string,params:{[key:string]:any}):void
}>>(Class:C) {return class extends Class {request(path:string,method:string,params:{[key:string]:any}) {console.debug("打印请求日志:",path,method,params);super.request(path,method,params);}}
}class CustomRequest {request(path:string,method:string,params:{[key:string]:any}) {console.log("请求完成");}
}let DecoratorRequest = createDecoratorRequest(CustomRequest);
let req = new DecoratorRequest();
req.request("http://localhost:8080/hello","GET",{id:13,value: "334"});
req.request("https://localhost:8080/file","POST",{name: "fire.txt"});// 打印请求日志: http://localhost:8080/hello GET { id: 13, value: '334' }
// 请求完成
// 打印请求日志: https://localhost:8080/file POST { name: 'fire.txt' }
// 请求完成

3.2 简单工厂模式

需求:输入手机品牌,生产出对于品牌的手机。

class Phone {}
class Apple extends Phone {}
class Huawei extends Phone {}type FactoryCreate = {(name:"apple") : Apple(name: "huawei") : Huawei
}let factoryCreate:FactoryCreate =
function createPhone(name:"apple"|"huawei"):Phone {if (name === "apple") return new Apple();return new Huawei();
}let phone1 = factoryCreate("apple");
let phone2 = factoryCreate("huawei");

3.3 建造者模式

需求:建造请求对象,要求执行顺序是:设置请求路径->设置请求方法->设置请求参数->发送。

class RequestBuilder {private path: string | null = nullprivate method: "GET" | "POST"  = "GET"private params: {[key:string]:any} | null = nullprivate constructor() {}static setPath(path: string):{setMethod(method: "GET" | "POST"):{setParams(params: {[key:string]:any}):{send():void}}} {let request = new RequestBuilder();request.path = path;return request;}setMethod(method: "GET" | "POST"):{setParams(params: {[key:string]:any}):{send():void}} {this.method = method;return this;}setParams(params: {[key:string]:any}):{send():void} {this.params = params;return this;}send() {console.log(this.path,this.method,this.params,"发送成功");}}RequestBuilder.setPath("/hello").setMethod("GET").setParams({id:111,value:-12}).send();

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Serilog .net下的新兴的日志框架

Serilog .net下的新兴的日志框架 1.Serilog简介 Serilog 是针对 .NET 应用程序的流行日志记录框架。它以其灵活性、易用性和可扩展性而闻名。借助 Serilog&#xff0c;开发人员可以轻松记录应用程序中的事件、错误和消息。它支持结构化日志记录&#xff0c;能够以结构化格式存…

贪心 55. 跳跃游戏 45.跳跃游戏 II

55. 跳跃游戏 题目&#xff1a; 给定非负数组&#xff0c;初始位置在数组第一格&#xff0c;数组值是可以选择的最大跳跃步数&#xff0c;判断能不能达到数组末尾。 示例 1: * 输入: [2,3,1,1,4] * 输出: true * 解释: 我们可以先跳 1 步&#xff0c;从位置 0 到达 位置 1,…

AWS EC2 如何 使用 SSM会话管理器登陆

首先只有特定版本的OS会默认附带SSM Agent。 预安装了 SSM Agent 的 Amazon Machine Images&#xff08;AMIs&#xff09; - AWS Systems Manager 其次EC的instance role必须有一个叫“AmazonSSMManagedInstanceCore”的策略 如何给IAM User赋权&#xff0c;让他们可以使用SSM…

appium :输入框控件为android.view.View 时输入内容(如:验证码、密码输入框)

问题背景 输入密码的组件信息为&#xff1a;<android.view.View resource-id“com.qq.ac.android:id/pwd_input”> 由于输入框控件是android.view.View&#xff0c;不是android.widget.EditText&#xff0c;所以只能点击&#xff0c;而启动appium后&#xff0c;会将输入…

Vue语音播报,不用安装任何包和插件,直接调用。

Vue语音播报功能可以通过使用浏览器提供的Web Speech API来实现。这个API允许你的应用程序通过浏览器朗读文本&#xff0c;不用安装任何包和插件&#xff0c;直接调用。以下是一个简单的介绍&#xff0c;演示如何在Vue中使用语音提示功能&#xff1a; 一、JS版本 <template…

XTU OJ 1339 Interprime 学习笔记

链接 传送门 代码 #include<bits/stdc.h> using namespace std;const int N1e610; //78498 我计算了一下&#xff0c;6个0的范围内有这么多个素数&#xff0c;所以开这么大的数组存素数 //计算的代码是一个循环 int prime[80000]; int a[N],s[N];//s数组是前缀和数组b…

高等数学上岸宝典笔记

①不单调的函数也可能有反函数 ②注意反函数与函数转换时的定义域与值域 ③收敛数列不一定有最值 收敛数列必有上界和下界&#xff0c;但不一定有最值&#xff0c;比如{An}1/n&#xff0c;下界为0&#xff0c;但永远取不到0 ④数列与其子数列的关系 例题&#xff1a; ⑤带根号…

Linux常用命令——cd命令

文章目录 1. 简介2. 命令参数3. 常见用法与实例3.1 基本用法3.2 使用绝对路径或相对路径3.3 使用特殊字符3.4 使用参数 4. 总结 1. 简介 cd命令是Linux系统中最基础且频繁使用的命令之一&#xff0c;用于改变当前工作目录。它是“change directory”的缩写&#xff0c;对于任何…

什么是WebP

WebP 是一种现代的图像格式&#xff0c;由 Google 开发&#xff0c;用于在 Web 上显示图像。它使用了有损压缩算法&#xff0c;可以显著减小图像的文件大小&#xff0c;同时保持较高的图像质量。 WebP 格式的主要特点包括&#xff1a; 更小的文件大小&#xff1a;相比于 JPEG …

网狐类源码游戏配置数据库数据(一键配置网狐数据库)

网狐类源码游戏配置数据库数据&#xff08;一键配置网狐数据库&#xff09; 一般拿到网狐的源码或组件&#xff0c;需要先附加或配置数据库&#xff0c;以下为全部需要更改数据的地方&#xff0c;这里以荣耀系列版本数据库为例&#xff1a; 1. 数据库设置 [RYPlatformDB].…

Redis7--基础篇5(管道、发布订阅)

管道是什么 管道(pipeline)可以一次性发送多条命令给服务端&#xff0c;服务端依次处理完完毕后&#xff0c;通过一条响应一次性将结果返回&#xff0c;通过减少客户端与redis的通信次数来实现降低往返延时时间。pipeline实现的原理是队列&#xff0c;先进先出特性就保证数据的…

【驱动】SPI驱动分析(二)-SPI驱动框架

SPI驱动框架 SPI驱动属于总线-设备-驱动模型的&#xff0c;与I2C总线设备驱动模型相比&#xff0c;大体框架是一样&#xff0c;他们都是实际的总线。总体框架如下图所示&#xff1a; 从上到下&#xff0c;分为三层&#xff0c;用户空间&#xff0c;内核空间&#xff0c;和硬件…

Verilog/System Verilog的常用内置函数(数字验证)

Verilog/System Verilog的常用内置函数&#xff08;数字验证&#xff09; 1、数学运算相关的内置函数 2、字符串传递相关的内置函数 1&#xff09;$ test$ plusarg 用于只输入字符串时 2&#xff09;$ value$ plusargs (user_string, variable) 既可以输入字符串也可以输入各种…

【驱动】串口驱动分析(一)-软件架构

区分不同的终端类型 串行端口终端&#xff08;/dev/ttySn&#xff09; 串行端口终端&#xff08;Serial Port Terminal&#xff09;是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作是一个字符设备。 有段时间这些串行端口设备通常被称为终端设备&#xff0…

vue项目下npm或yarn下安装echarts多个版本

最近在大屏展示的时候&#xff0c;用到了百度的echarts图表库&#xff0c;看完效果图后&#xff0c;又浏览了一下echarts官网案例&#xff0c;大同小异。但是搬砖过程中发现实际效果和demo相差甚远&#xff0c;一番折腾发现&#xff0c;项目中安装的是echarts4.x版本&#xff0…

二进制求和

这篇文章会收录到 : 算法通关村第十三关-白银挑战数字与数学高频问题-CSDN博客 二进制求和 描述 : 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 题目 : LeetCode 67.二进制求和 : 67. 二进制求和 分析 : 这个题也是用字符串来表示数据的…

MySQL cAPI踩下的坑

1.使用mysql_real_query函数查询之后没有对结果集进行释放 MySQL中&#xff0c;如果查询之后没有释放结果集&#xff0c;会导致MySQL无法进行下一步操作 使用mysql_errno获取错误码&#xff1a;2014 正确做法 //执行查询 mysql_real_query(mysql_, stmt_str.c_str(), length…

深入理解Zookeeper系列-1.初识Zoookeeper

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理&#x1f525;如果感觉博主的文章还不错的话&#xff…

设计模式-创建型模式之原型、建造者设计模式

文章目录 七、原型模式八、建造者模式 七、原型模式 原型模式&#xff08;Prototype Pattern&#xff09;是用于创建重复的对象&#xff0c;同时又能保证性能。它提供了一种创建对象的最佳方式。 这种模式是实现了一个原型接口&#xff0c;该接口用于创建当前对象的克隆。当直…

Python实现FA萤火虫优化算法优化循环神经网络回归模型(LSTM回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 萤火虫算法&#xff08;Fire-fly algorithm&#xff0c;FA&#xff09;由剑桥大学Yang于2009年提出 , …