1.枚举enum
1.1、数字枚举:
使用枚举我们可以定义一些带名字的常量,使用枚举可以清晰地表达意图或创建一组有区别的用例,程序中能灵活的使用枚举(enum
),会让程序有更好的可读性
1.2、字符串枚举:
由于字符串枚举没有自增长的行为,字符串枚举可以很好的序列化,还有其他很多枚举类型,但是不常用,用到时,才去研究吧,比如异型枚举
1.3、const
枚举:
大多数情况下,枚举是十分有效的方案。 然而在某些情况下需求很严格。 为了避免在额外生成的代码上的开销和额外的非直接的对枚举成员的访问,我们可以使用 const
枚举。
常量枚举通过在枚举上使用 const
修饰符来定义。
1.4、外部枚举:
枚举是不是看起来有点类似js中镜像翻转后的数组,又有点像序列化之后的对象是吧?
我开始也是这么认为的,那么这个枚举类型到底有什么用处,或者说和已有类型(对象和数组)有什么使用上的区别呢?
在百度了一些资料后,我得出的结论是:
ts中的枚举类型和普通的js对象本质上没有区别,只是对于开发者来说,相较于直接使用值类型去做判断,枚举类型更易读,能够提升代码的可读性和易维护性。
2、泛型(难点)
泛型的定义使用<>
(尖角号)进行定义的,里面写类型参数,一般可以用T来表示,简单来说,泛型中的 T就像一个占位符,或者说一个变量,在使用的时候可以把
定义的类型像参数一样传入,它可以原封不动地输出。(泛型就是动态灵活的去控制类型)
泛型在造轮子的时候经常使用,因为造轮子很多东西都需要灵活性。泛型给了我们很好的灵活性。需要注意的是,如果函数定义了多个泛型,使用时要对应的定义出具体的类型
1、泛型的默认参数
2、泛型约束
第1项上就全是string的方法了,如下:
函数副作用操作:
如我们在项目中写api接口的时候,想知道函数返回的接口数据结构,那么我们就可以像下面那种方式写:
3、泛型约束类
4、泛型约束接口
使用泛型,也可以对 interface 进行改造,让 interface 更灵活
5、泛型定义数组
泛型的用处还有很多地方,就不一样举例
下面用一张图来概括泛型吧:
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文件里的命名空间名称一样, 尽管是不同的文件,它们仍是同一个命名空间,并且在使用的时候就如同它们在一个文件中定义的一样。
- 因为不同文件之间存在依赖关系,所以我们还是要采用上面方式加入了引用标签来告诉编译器文件之间的关联,只是使用的时候可以直接用命名空间里面的方法,不用在加上命名空间去点取。
最后小结一下:
命名空间本质是一个闭包,用来隔离作用域
TS命名空间是对全局变量时代的兼容
在一个完全模块化的系统中,不必使用命名空间