TypeScript学习笔记
一、什么是TypeScript
- 定义:TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准
- 特点:
- 支持最新的JavaScript新特特性
- 支持代码静态检查
- 支持诸如C,C++,Java,Go等后端语言中的特性 (枚举、泛型、类型转换、命名空间、声明文件、类、接口等)
二、TypeScript与JavaScript的区别
JavaScript:是弱类型, 很多错误只有在运行时才会被发现
TypeScript:提供了一套静态检测机制, 可以帮助我们在编译时就发现错误
三、基础类型
1、布尔值
- boolean 表示逻辑值:true 和 false
2、数字
- number 双精度 64 位浮点值。它可以用来表示整数和分数。
let binaryLiteral: number = 0b1010; // 二进制
let octalLiteral: number = 0o744; // 八进制
let decLiteral: number = 6; // 十进制
let hexLiteral: number = 0xf00d; // 十六进制
3、字符串
- string 一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式
let name: string = "Runoob";
let years: number = 5;
let words: string = `您好,今年是 ${ name } 发布 ${ years + 1} 周年`;
4、数组
声明变量为数组
// 在元素类型后面加上[]
let arr: number[] = [1, 2];
// 或者使用数组泛型
let arr: Array<number> = [1, 2];
5、元组 Tuple
元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同
let x: [string, number];
x = ['Runoob', 1]; // 运行正常
x = [1, 'Runoob']; // 报错
console.log(x[0]); // 输出 Runoob
6、枚举
- enum 枚举类型用于定义数值集合
enum Color {Red, Green, Blue};
let c: Color = Color.Blue;
console.log(c); // 输出 2
7、任意值
- any 声明为 any 的变量可以赋予任意类型的值
8、空值
- void 用于标识方法返回值的类型,表示该方法没有返回值
9、Null 和 Undefined
- null 表示对象值缺失
- undefined 用于初始化变量为一个未定义的值
10、Never
- never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
11、类型断言
- 含义:类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。
- 类型断言有两种形式:
- 一是“尖括号”语法:
let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length;
- 另一个为as语法:
let someValue: any = "this is a string"; let strLength: number = (someValue as string).length; 两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在TypeScript里使用JSX时,只有as语法断言是被允许的。
四、变量声明
TypeScript是JavaScript的超集,所以它本身就支持let和const- var 声明
声明变量的类型及初始值: var [变量名] : [类型] = 值;
变量作用域
-
定义: 变量作用域指定了变量定义的位置。
-
作用:程序中变量的可用性由变量作用域决定。
-
类型: TypeScript 有以下几种作用域:
-
全局作用域:全局变量定义在程序结构的外部,它可以在你代码的任何位置使用。
-
类作用域:这个变量也可以称为 字段。类变量声明在一个类里头,但在类的方法外面。 该变量可以通过类的对象来访问。类变量也可以是静态的,静态的变量可以通过类名直接访问。
-
局部作用域:局部变量,局部变量只能在声明它的一个代码块(如:方法)中使用。
-
五、Number
从类型兼容性上看,原始类型兼容对应的对象类型,反过来对象类型不兼容对应的原始类型
下表列出了 Number 对象支持的属性:
属性 | 描述 |
---|---|
MAX_VALUE | 可表示的最大的数,MAX_VALUE 属性值接近于 1.79E+308。大于 MAX_VALUE 的值代表 “Infinity” |
MIN_VALUE | 可表示的最小的数,即最接近 0 的正数 (实际上不会变成 0)。最大的负数是 -MIN_VALUE,MIN_VALUE 的值约为 5e-324。小于 MIN_VALUE (“underflow values”) 的值将会转换为 0 |
NaN | 非数字值(Not-A-Number) |
NEGATIVE_INFINITY | 负无穷大,溢出时返回该值。该值小于 MIN_VALUE |
POSITIVE_INFINITY | 正无穷大,溢出时返回该值。该值大于 MAX_VALUE |
prototype | Number 对象的静态属性。使您有能力向对象添加属性和方法 |
constructor | 返回对创建此对象的 Number 函数的引用 |
Number对象 支持以下方法:
方法 | 作用 |
---|---|
toExponential() | 把对象的值转换为指数计数法 |
toFixed() | 把数字转换为字符串,并对小数点指定位数 |
toLocaleString() | 把数字转换为字符串,使用本地数字格式顺序 |
toPrecision() | 把数字格式化为指定的长度。 |
toString() | 把数字转换为字符串,使用指定的基数。数字的基数是 2 ~ 36 之间的整数。若省略该参数,则使用基数 10 |
valueOf() | valueOf() 返回一个 Number 对象的原始数字值 |
六、TypeScript Array(数组)
1、声明
TypeScript 声明数组的语法格式如下所示:
var array_name[:datatype]; //声明
array_name = [val1,val2,valn..] //初始化
或者直接在声明时初始化:
var array_name[:datatype] = [val1,val2…valn]
2、Array 对象
Array 对象的构造函数接受以下两种值:
- 表示数组大小的数值
var arr_names:number[] = new Array(4)
for(var i = 0; i<arr_names.length; i++) {
arr_names[i] = i * 2
console.log(arr_names[i])
}
- 初始化的数组列表,元素使用逗号分隔值
var sites:string[] = new Array("Google","Runoob","Taobao","Facebook")
for(var i = 0;i<sites.length;i++) {
console.log(sites[i])
}
3、多维数组
- 定义:一个数组的元素可以是另外一个数组,这样就构成了多维数组。
最简单的多维数组是二维数组,定义方式如下:
var arr_name:datatype[][]=[ [val1,val2,val3],[v1,v2,v3] ]
数组的一些方法:
方法 | 作用 |
---|---|
concat() | 连接两个或更多的数组,并返回结果 |
every() | 检测数值元素的每个元素是否都符合条件 |
filter() | 检测数值元素,并返回符合条件所有元素的数组 |
forEach() | 数组每个元素都执行一次回调函数 |
indexOf() | 搜索数组中的元素,并返回它所在的位置。 |
reduce() | 将数组元素计算为一个值(从左到右) |
reverse() | 反转数组的元素顺序。 |
slice() | 选取数组的的一部分,并返回一个新数组。 |
splice() | 从数组中添加或删除元素 |
七、TypeScript Map 对象
1、定义
Map 对象保存键值对,并且能够记住键的原始插入顺序。
任何值(对象或者原始值) 都可以作为一个键或一个值。
2、属性方法
方法 | 作用 |
---|---|
map.clear() | 移除 Map 对象的所有键/值对 |
map.set() | 设置键值对,返回该 Map 对象 |
map.get() | 返回键对应的值,如果不存在,则返回 undefined |
map.has() | 返回一个布尔值,用于判断 Map 中是否包含键对应的值。map.delete() |
map.keys() | 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 |
3、Map迭代
let nameSiteMapping = new Map();
nameSiteMapping.set("Google", 1);
nameSiteMapping.set("Runoob", 2);
nameSiteMapping.set("Taobao", 3);
// 迭代 Map 中的 key
for (let key of nameSiteMapping.keys()) {
console.log(key);
}
// 迭代 Map 中的 value
for (let value of nameSiteMapping.values()) {
console.log(value);
}
// 迭代 Map 中的 key => value
for (let entry of nameSiteMapping.entries()) {
console.log(entry[0], entry[1]);
}
// 使用对象解析
for (let [key, value] of nameSiteMapping) {
console.log(key, value);
}
八、元组
1、定义
如果存储的元素数据类型不同,则需要使用元组。
元组中允许存储不同类型的元素,元组可以作为参数传递给函数。
2、元组运算
我们可以使用以下两个函数向元组添加新元素或者删除元素:
-
push() 向元组添加元素,添加在最后面。
-
pop() 从元组中移除元素(最后一个),并返回移除的元素。
var mytuple = [10,"Hello","World","typeScript"];
console.log("添加前元素个数:"+mytuple.length) // 返回元组的大小
mytuple.push(12) // 添加到元组中
console.log("添加后元素个数:"+mytuple.length)
console.log("删除前元素个数:"+mytuple.length)
console.log(mytuple.pop()+" 元素从元组中删除") // 删除并返回删除的元素
console.log("删除后元素个数:"+mytuple.length)
3、更新元组
元组是可变的,这意味着我们可以对元组进行更新操作:
var mytuple = [10, "Runoob", "Taobao", "Google"]; // 创建一个元组
console.log("元组的第一个元素为:" + mytuple[0])
// 更新元组元素
mytuple[0] = 121
console.log("元组中的第一个元素更新为:"+ mytuple[0])
九、TypeScript 接口
1、功能
接口是一系列抽象方法的声明,是一些方法特征的集。
这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。
2、定义
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
3、属性
- 只读属性
只读属性用于限制只能在对象刚刚创建的时候修改其值
此外 TypeScript 还提供了 ReadonlyArray<T> 类型,它与 Array<T> 相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改。
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
- 任意属性
- 当一个接口中除了包含必选和可选属性之外,还允许有其他的任意属性,可以使用
索引签名
的形式
- 当一个接口中除了包含必选和可选属性之外,还允许有其他的任意属性,可以使用
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
4、联合类型和接口
- 适用情形:一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型。
interface RunOptions {
program:string;
commandline:string[]|string|(()=>string);
}
// commandline 是字符串
var options:RunOptions = {program:"test1",commandline:"Hello"};
console.log(options.commandline)
// commandline 是字符串数组
options = {program:"test1",commandline:["Hello","World"]};
console.log(options.commandline[0]);
console.log(options.commandline[1]);
// commandline 是一个函数表达式
options = {program:"test1",commandline:()=>{return "**Hello World**";}};
var fn:any = options.commandline;
console.log(fn());
5、接口继承
-
Typescript 允许接口继承多个接口。
-
继承使用关键字 extends。
单接口继承语法格式:
Child_interface_name extends super_interface_name
//样例
interface Person {
age:number
}
interface Musician extends Person {
instrument:string
}
var drummer = <Musician>{};
drummer.age = 27
drummer.instrument = "Drums"
console.log("年龄: "+drummer.age)
console.log("喜欢的乐器: "+drummer.instrument)
多接口继承语法格式:
Child_interface_name extends super_interface1_name, super_interface2_name,…,super_interfaceN_name
//样例
interface IParent1 {
v1:number
}
interface IParent2 {
v2:number
}
interface Child extends IParent1, IParent2 { }
var Iobj:Child = { v1:12, v2:23}
console.log("value 1: "+Iobj.v1+" value 2: "+Iobj.v2)
十、TypeScript 类
1、特点
- TypeScript 是面向对象的 JavaScript。
- 类描述了所创建的对象共同的属性和方法。
2、类的使用
- 创建类的数据成员
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log("发动机为 : "+this.engine)
}
}
- 创建实例化对象
var object_name = new class_name([ arguments ])
var obj = new Car("Engine 1")
3、类的继承
- 语法格式如下:
class child_class_name extends parent_class_name - 实例
//类的继承:实例中创建了 Shape 类,Circle 类继承了 Shape 类,Circle 类可以直接使用 Area 属性:
TypeScript
class Shape {
Area:number
constructor(a:number) {
this.Area = a
}
}
class Circle extends Shape {
disp():void {
console.log("圆的面积: "+this.Area)
}
}
var obj = new Circle(223);
obj.disp()
注意:子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承
4、访问控制修饰符
-
public(默认) : 公有,可以在任何地方被访问
-
protected : 受保护,可以被其自身以及其子类访问
protected与private区别:protected成员在派生类中仍然可以访问
-
private : 私有,只能被其定义所在的类访问
十一、TypeScript 命名空间
1、定义
- 命名空间定义了标识符的可见范围,一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的
- TypeScript 中命名空间使用
namespace
来定义
2、功能
- 在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中
3、运用
- 语法格式如下:
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { }
export class SomeClassName { }
}
- 使用
要在另外一个命名空间调用语法格式为:
SomeNameSpaceName.SomeClassName;
如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:
/// <reference path = "SomeFileName.ts" />
4、使用其它的JavaScript库
-
外部命名空间
流行的程序库D3在全局对象d3里定义它的功能。 因为这个库通过一个<script>标签加载(不是通过模块加载器),它的声明文件使用内部模块来定义它的类型。 为了让TypeScript编译器识别它的类型,我们使用外部命名空间声明
declare namespace D3 {
export interface Selectors {
select: {
(selector: string): Selection;
(element: EventTarget): Selection;
};
}
export interface Event {
x: number;
y: number;
}
export interface Base extends Selectors {
event: Event;
}
}
declare var d3: D3.Base;
十二、模块
1、特点
- 模块在其自身的作用域里执行,而不是在全局作用域里;
- 这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。
- 相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用import形式之一。
2、导出
- 导出声明
任何声明(比如变量,函数,类,类型别名或接口)都能够通过添加export关键字来导出。 - 导出语句
导出语句很便利,有时候我们可能需要对导出的部分重命名:
class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };
- 重新导出
我们经常会去扩展其它模块,并且只导出那个模块的部分内容。 重新导出功能并不会在当前模块导入那个模块或定义一个新的局部变量。
ParseIntBasedZipCodeValidator.ts
export class ParseIntBasedZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && parseInt(s).toString() === s;
}
}
// 导出原先的验证器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
3、导入
- 导入声明
可以使用以下import形式之一来导入其它模块中的导出内容。
//导入一个模块中的某个导出内容
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator = new ZipCodeValidator();
十三、声明合并
1、定义
- “声明合并”是指编译器将针对同一个名字的两个独立声明合并为单一声明。
- 合并后的声明同时拥有原先两个声明的特性。 任何数量的声明都可被合并;不局限于两个声明。
2、合并接口
- 最简单也最常见的声明合并类型是接口合并。
- 从根本上说,合并的机制是把双方的成员放到一个同名的接口里。
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};
3、合并命名空间
-
对于命名空间的合并:模块导出的同名接口进行合并,构成单一命名空间内含合并后的接口。
-
对于命名空间里值的合并:如果当前已经存在给定名字的命名空间,那么后来的命名空间的导出成员会被加到已经存在的那个模块里。
namespace Animal {
let haveMuscles = true;
export function animalsHaveMuscles() {
return haveMuscles;
}
}
namespace Animal {
export function doAnimalsHaveMuscles() {
return haveMuscles; // <-- error, haveMuscles is not visible here
}
}
本文章参考如下:
TypeScript手册
菜鸟教程
掘金TypeScript