首页 > 其他分享 >TS进阶知识点

TS进阶知识点

时间:2023-02-19 18:57:39浏览次数:43  
标签:知识点 return 进阶 TS 空间 ts 泛型 命名 namespaceA

1.枚举enum

1.1、数组枚举:

使用枚举我们可以定义一些带名字的常量,使用枚举可以清晰地表达意图或创建一组有区别的用例,程序中能灵活的使用枚举(enum),会让程序有更好的可读性

enum Status {     text1= 1,     text2,     text3, } 这里能打印出枚举的值(也有叫下标的),那如果我们知道下标后,也可以通过反差的方法,得到枚举的值,此时text1就为1,text2为2,text3为3 如果text1没有赋值,那么排序就直接从0开始排,如果从中间位置开始

1.2、字符串枚举:

enum Direction {     Up = "UP",     Down = "DOWN",     Left = "LEFT",     Right = "RIGHT", }

由于字符串枚举没有自增长的行为,字符串枚举可以很好的序列化,还有其他很多枚举类型,但是不常用,用到时,才去研究吧,比如异型枚举

2、泛型(难点)

泛型的定义使用<>(尖角号)进行定义的,里面写类型参数,一般可以用T来表示,简单来说,泛型中的 T就像一个占位符,或者说一个变量,在使用的时候可以把

定义的类型像参数一样传入,它可以原封不动地输出。(泛型就是动态灵活的去控制类型)

泛型在造轮子的时候经常使用,因为造轮子很多东西都需要灵活性。泛型给了我们很好的灵活性。需要注意的是,如果函数定义了多个泛型,使用时要对应的定义出具体的类型

function join<T, P>(first: T, second: P) {     return `${first}${second}`;   } join < number, string > (1, "2"); 虽然泛型也可以自己进行类型推断,但是不建议,最好在使用时指明其类型,这会让你的代码简单易读写。 function join1<T, P>(first: T, second: P) {     return `${first}${second}`;   } join1(1, "2");  比如:我们写一个类,实现对我们实例化传入的值,进行一个输出,可能会像下面写: class SelectGirl {     constructor(private girls: string[]) {}     getGirl(index: number): string {       return this.girls[index];     }   } const selectGirl = new SelectGirl(["大脚", "刘英", "晓红"]); console.log(selectGirl.getGirl(1));  但是如果我们把实例化时传入的参数改成[12,122,33],我们在进行取值,这样返回的类型就不再说固定的一个类型了,此时就需要使用泛型了 class SelectGirl2<T> {     constructor(private girls: T[]) {}     getGirl(index: number): T {       return this.girls[index];     }   }   const selectGirl2 = new SelectGirl2<string>(["大脚", "刘英", "晓红"]);   console.log(selectGirl2.getGirl(1));

1、泛型的默认参数

interface Print<T = string> {     name: T   } const myPrint:Print = {     name:'2323' } function print<T>(arg: T):T{     return arg } print<string>('1212')

 2、泛型约束

假设现在有一个函数,打印传入参数的长度,我们是这么写的 function printLength<T>(arg: T): T {     console.log(arg.length) } 因为不确定T是否有length属性,会报错,现在想要约束这个泛型,就一定要有length属性,我们就可以结合interface来约束 interface ILength{     length: number } //泛型继承接口 function printLength<T extends ILength>(arg: T): T {     console.log(arg.length)     return arg } printLength({length: 4, name: 'ceshi'}) 如果调用时传入的参数里面没有length属性,那么ts就会报错,提示必须包含次属性,这其中的关键是<T extends ILength>,让这个泛型继承接口,这样就会约束泛型啦 处理多个函数参数: 现在有这么一个函数,传入一个只有两项的元组,交换元组的第 0 项和第 1 项,返回这个元组。 function swap(tuple) {     return [tuple[1], tuple[0]] } 这么写,我们就丧失了类型,用泛型来改造一下 们用 T 代表第 0 项的类型,用 U 代表第 1 项的类型 function swap1<T, U>(tuple: [T, U]): [U, T]{     return [tuple[1], tuple[0]] } swap1<number, string>([12, 'hhhh']) 这样就可以实现了元组第 0 项和第 1 项类型的控制 第 0 项上全是 number 的方法,如下:

 

 第1项上就全是string的方法了,如下:

 

函数副作用操作:

如我们在项目中写api接口的时候,想知道函数返回的接口数据结构,那么我们就可以像下面那种方式写:

interface UserInfo {     name: string     age: number } function request<T>(url:string): Promise<T> {     return fetch(url).then(res => res.json()) } request<UserInfo>('user/info').then(res =>{     console.log(res) }) 样就能很舒服地拿到接口返回的数据类型,开发效率大大提高

 

 

3、泛型约束类

定义一个栈,有入栈和出栈两个方法,如果想入栈和出栈的元素类型统一,就可以这么写: class Stack<T> {     public data: T[] = []     push(item:T) {         return this.data.push(item)     }     pop():T | undefined {         return this.data.pop()     } } const s1 = new Stack<number>() s1.push(12) console.log(s1.data) 这样,入栈一个字符串就会报错

 

 

特别注意的是,泛型无法约束类的静态成员

 

 4、泛型约束接口

使用泛型,也可以对 interface 进行改造,让 interface 更灵活

interface IKeyValue<T, U> {     key: T     value: U } const k1:IKeyValue<number, string> = { key: 18, value: 'lin'} const k2:IKeyValue<string, number> = { key: 'lin', value: 18}

5、泛型定义数组

 定义一个数组,我们之前是这么写的:const arr: number[] = [1,2,3] 现在这么写也可以:const arr: Array<number> = [1,2,3] 实战:泛型约束后端接口参数类型 interface API {     '/book/detail': {         id: number,     },     '/book/comment': {         id: number         comment: string     } } function request<T extends keyof API>(url: T, obj: API[T]) {     return axios.post(url, obj) } request('/book/comment', {     id: 1,     comment: '非常棒!' })  如果路径写错了,就会提醒:

 

 泛型的用处还有很多地方,就不一样举例

下面用一张图来概括泛型吧:

 

 3.命名空间

命名空间简介:

命名空间(在早期版本的 TypeScript 中称为“内部模块”)是一种用于组织和分类代码的 TypeScript 特定方式,使你能够将相关代码组合在一起。 命名空间允许将与业务规则相关的变量、函数、接口或类分组到一个命名空间,将安全性分组到另一个命名空间。

命名空间内的代码将从全局范围拉入到命名空间范围。 这种布局有助于避免全局命名空间中组件之间的命名冲突,并且在与可能使用类似组件名称的分布式开发团队合作时也会有好处。

命名空间特点

  • 减少全局范围内的代码量,限制“全局范围污染”。
  • 为名称提供上下文,有助于减少命名冲突。
  • 提高可重用性。

TypeScript 中命名空间使用 namespace 来定义,例如:

namespace namespaceA{
	export interface interfaceA{}
	export class classA{}
	function getUserInfo() {
		let name = getName()
		return console.log(name + ',I am 26 years old')
	}
	function getName() {
		return 'my name is Yj'
	}
}

interfaceA  // false,没有添加命名空间名称前缀namespaceA
namespaceA.interfaceA    // true
namespaceA.classA  // true
namespaceA.getName  // false,没有export关键字
namespaceA.getUserInfo  // 'my name is Yj, I am 26 years old'
以上定义了一个命名空间 namespaceA,如果我们需要在外部可以调用 namespaceA中的类和接口,则需要在类和接口添加 export 关键字。命名空间中定义的所有组件的作用域都限定为命名空间,并从全局范围中删除使用嵌套命名空间组织代码:在命名空间中嵌套命名空间,从而提供更多的选项来组织代码,个人理解类似于在一个对象里面找对象属性的属性。
namespace namespaceA{
	export namespaceB{
		export functionA() {
			namespaceC.functionB
		}
	}
	export namespaceC{
		export functionB() {
			return console.log('这是命名空间c里面的函数b!')
		}
		export functionC() {
			return console.log('这是命名空间C里面的函数C!')
		}
	}
}

namespaceA.namespaceB.functionA  // 这是命名空间c里面的函数b!
namespaceA.namespaceC.functionC  // 这是命名空间C里面的函数C!
定义命名空间别名:
TypeScript 创建一个易于导航的嵌套命名空间层次结构。 但是,随着嵌套命名空间变得越来越复杂,你可能需要创建一个别名来缩短和简化代码。 为此,请使用 import 关键字。
//namespaceA 和 namespaceB来自上面的代码
import nameA = namespaceA.namespaceB;
nameA.functionA();  // '这是命名空间c里面的函数b!'
编译单一文件命名空间:

编译单一文件命名空间的方式与编译任何其他 TypeScript 文件的方式相同。 因为命名空间是一个只包含 TypeScript 的构造,所以会从生成的 JavaScript 代码中删除它们,并将其转换为必要时嵌套的变量,以形成类似命名空间的对象。

如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:

/// <reference path = "SomeFileName.ts" />

使用多文件命名空间来组织代码:

可以通过跨多个 TypeScript 文件共享命名空间来扩展它们。 如果在多个文件中具有彼此相关的命名空间,则必须添加 reference 标记,使 TypeScript 编译器知道文件之间的关系。 例如,假定你有三个 Typescript 文件:

  • interfaces.ts,它声明包含某些接口定义的命名空间。
  • functions.ts,该文件使用在 interfaces.ts 中实现接口的函数声明命名空间。
  • main.ts,它调用 functions.ts 中的函数,并表示应用程序的主代码。

若要告知 TypeScript interfaces.ts 与 functions.ts 之间的关系,请在 functions.ts 顶部使用三斜杠 (///) 语法向 interfaces.ts 添加 reference。 然后,在与 interfaces.ts 和 functions.ts 关联的 main.ts 中,将 reference 添加到这两个文件。

 

 

  • 如果对多个文件进行引用,请从最高级别的命名空间开始,然后逐渐向下。 在编译文件时,TypeScript 将使用此顺序。
  • 如果几个ts文件里的命名空间名称一样, 尽管是不同的文件,它们仍是同一个命名空间,并且在使用的时候就如同它们在一个文件中定义的一样。
  • 因为不同文件之间存在依赖关系,所以我们还是要采用上面方式加入了引用标签来告诉编译器文件之间的关联,只是使用的时候可以直接用命名空间里面的方法,不用在加上命名空间去点取。

 

 

 

标签:知识点,return,进阶,TS,空间,ts,泛型,命名,namespaceA
From: https://www.cnblogs.com/yihuanhuan/p/17134921.html

相关文章

  • C语言进阶--有符号与无符号
    数据类型的最高位用于标识数据的符号-最高位为1,表明这个数为负数-最高位为0,表明这个数为正数*在计算机内部用补码表示有符号数-正数的补码就是正数本身-负数......
  • Bootstrap框架
    导入:为什么要使用BootStrapBootstrap,来自Twitter,是一款受欢迎的前端框架。Bootstrap是基于HTML、CSS、JAVASCRIPT的,它简洁灵活,使得Web开发更加快捷。大家可以在......
  • linux limits.conf 生效,linux修改limits.conf不生效
    正常情况下,/etc/security/limits.conf的改动,应该在下次访问时就生效才对。一、修改方法1.临时方法为了优化linux性能,可能需要修改这个最大值。临时修改的话ulimit-n......
  • echarts实现3个y轴的图表
    option={xAxis:{type:'category',data:['Mon','Tue','Wed','Thu','Fri','Sat','Sun','Mon','Tue','Wed','Thu',]}......
  • python requests 最牛攻略
    目录安装ReuqestsHTTP简介什么是HTTPHTTP工作原理HTTP的9种请求方法HTTP状态码requests快速上手requests发起请求的步骤requests发起请求的两种方式请求参数发起GET......
  • Golang基础-Structs与Methods
    将struct定义为一种类型CarNewCar函数return&Car{},返回指针//car.gopackageelon//Carimplementsaremotecontrolledcar.typeCarstruct{ speed......
  • AndroidApex技术分析调研1-apexd-bootstrap执行流程分析
    分析代码基线android10-releaseAPEX:AndroidPonyEXpress安卓运行环境AndroidRuntime(ART)将会在安卓12中,添加到ProjectMainline当中,这意味着可以通过GooglePlay商店......
  • LabVIEW|知识点:XML文件格式
      XML(eXtensibleMarkupLanguage)是一种目前广泛使用的数据传输和存储的格式,其本质上是一种文本文件,可以使用任何一个文本编辑工具打开和修改。类似于HTML,XML被设计为具......
  • robotframework接口请求常用关键字:RequestsLibrary
    ------------摘抄自51Testing软件测试网站------------一、版本对比RequestsLibrary最新版本为2021.4.22号发布的0.91版本,适配python2.x和python3.x,只需一句pipinstall......
  • 软件报错“Component 'mscomctl.ocx' or one of its dependencies not correctlyregis
    报错图   报错原因 mscomctl.ocx是公用ActiveX插件控制模块,MSCOMCTL.OCX为Windows的一个动态链接库,如果某程序是用它开发出来的,那么该程序的运行就有可能需要......