参考文章:
介绍与环境配置
TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持,它由 Microsoft 开发,代码开源于 GitHub 上。近几年,TypeScript 发展非常迅猛,Google 更是将其应用到 Angular2 的开发中。
要使用 TypeScript 语法,首先需要安装 typescript 模块,在全局环境下使用 npm 安装这个模块:npm install -g typescript
。
安装完成后即可编写 TypeScript 脚本(文件后缀名.ts),之后在终端中输入tsc xx.ts
即可编译”xx.ts”文件并生成”xx.js”文件,接着 node 环境下运行该 JavaScript 文件即可输出结果。
数据类型
变量声明
TypeScript 中,声明变量经常会附加变量类型的声明。数据类型分为五种原始(基本)数据类型和对象类型,变量声明使用 let 关键字,基本类型的变量声明如下:
let numVal: number = 10; // 数值类型
let strVal: string = 'Hello'; // 字符串类型
let boolVal: boolean = true; // 布尔类型
let undefinedVal: undefined = undefined; // Undefined类型
let nullVal: null = null; // null类型
TypeScript 新增了一种新类型——任意类型 Any,这种数据类型代表其他所有的数据类型。声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。
let anyVal: any = 'World';
console.log(anyVal, anyVal.toUpperCase());
anyVal = 100;
console.log(anyVal);
模板字符串
TypeScript 可以使用模板字符串,用法与ES6基本一致,模板字符串形式为一对”`”符号包含内容,内容中的”${xxx}”会被识别为代码,执行后再加载指定位置。
let numVal: number = 10; // 数值类型
let strVal: string = 'Hello'; // 字符串类型
let boolVal: boolean = true; // 布尔类型
let undefinedVal: undefined = undefined; // Undefined类型
let nullVal: null = null; // Null类型
let modleStr = `numVal: ${numVal},
strVal: ${strVal},
boolVal: ${boolVal},
undefinedVal: ${undefinedVal},
nullVal: ${nullVal}.`;
console.log(modleStr);
类型推论
先声明变量,再给变量赋值,这种做法是允许的:
let noTypeVal;
noTypeVal = 'WORLD'; // 没有声明类型,类型推论为String类型
console.log(noTypeVal.toLowerCase());
以上代码中少了声明变量类型的操作,这种做法不会报错,这是因为 TypeScript 会在没有明确的指定类型的时候推测出一个类型,这个过程被称为类型推论。如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查。
但是,不推荐使用这种不事先声明类型的做法。
联合类型
联合类型表示取值可以为多种类型中的一种,联合类型使用”|”分隔每个类型。当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法。
let unionTypeVal: string | number;
unionTypeVal = '1';
console.log(unionTypeVal);
unionTypeVal = 1;
console.log(unionTypeVal);
接口
接口是对行为的抽象,而具体如何行动需要由类去实现,接口一般首字母大写,赋值的时候,变量的形状必须和接口的形状保持一致。
接口其实就是对 JavaScript Object 内部的数据进行了一次类型约束。
interface Animal {
type: string;
readonly id: number;
info?: string;
[propName: string]: number | string;
};
const cat: Animal = {
type: 'Cat',
id: 1,
info: 'Has different color',
};
const dog: Animal = {
type: 'Dog',
id: 2,
isHealthy: true, // 不能将类型“boolean”分配给类型“string | number”。
};
console.log(cat, dog);
readonly 用于定义只读字段,只读属性指定字段只能在创建的时候被赋值,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候。
?:
定义的是可选属性,可选属性的含义是该属性可以不存在。
[propName: string]: number | string
定义了任意属性只能取 number 或 string 类型的值,一旦定义了任意属性,则确定属性和可选属性都必须是它的子属性。
函数
一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出(如果没有输出结果则应定义为 void 类型)都考虑到。输入多余的(或者少于要求的)参数,是不被允许的。传入的参数可以设置为可选、默认值等形式。
函数的形式
函数声明的形式比较简单:
function add(num1: number, num2?: number): number {
return num1 + (num2 || 0);
}
function sub(num1: number, num2: number = 0): void {
console.log(num1 - num2);
}
console.log(add(1, 2), add(2)); // 5
sub(5, 3); // 2
函数表达式中,”=>”表示函数的定义,左边是输入类型,右边是输出类型:
let add2: (num1: number, num2: number) => number =
function (num1: number, num2: number): number {
return num1 + num2;
};
console.log(add2(1, 2));
可进一步优化:
type AddFnType = (num1: number, num2: number) => number;
let add2: AddFnType = function (num1, num2) {
return num1 + num2;
};
console.log(add2(1, 2));
参数获取技巧
我们可以使用”…items”获取函数剩余参数,然后用forEach()
遍历:
function log(...items: any[]): void {
items.forEach(function (e, i) {
console.log(i + ': ' + e);
});
}
log('1', 2, true);
函数类型参数
给函数A传入函数B,函数A在具体时机执行函数B,这种场景的函数B称为”回调函数”,TypeScript 中你可能会这样实现以上场景:
function receiveInfo(callback: Function) {
...
}
receiveInfo(function(name, age, todo) {
...
});
但是,TypeScript 并不推荐使用”Function”这种类型,更推荐用以下写法:
type ReceiveInfoCallback = (name: string, age: number, todo: string) => void;
/**
* 或
* interface ReceiveInfoCallback {
* (name: string, age: number, todo: string): void
* }
*/
function receiveInfo(callback: ReceiveInfoCallback) {
...
}
receiveInfo(function(name, age, todo) {
...
});
类型断言
有时候你会遇到这样的情况,你会比 TypeScript 更了解某个值的详细信息。通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。
类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。它没有运行时的影响,只是在编译阶段起作用。TypeScript会假设你,已经进行了必须的检查。
function getLength(something: string | number): number {
// 断言something是string类型
if ((<string>something).length) {
return (<string>something).length;
} else {
return something.toString().length;
}
}
console.log(getLength(123));
断言的有两种写法,一种是使用<类型>
的形式(如上段代码),另一种是使用as
,使用as
对以上代码进行改写,结果如下:
function getLength(something: string | number): number {
// 断言something是string类型
if ((something as string).length) {
return (something as string).length;
} else {
return something.toString().length;
}
}
console.log(getLength(123));
内置对象
JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。常用的内置对象有 Boolean、Error、Date、RegExp 等。
let boolObj: Boolean = new Boolean(1);
let errorObj: Error = new Error('Error occurred');
let dateObj: Date = new Date();
let regexpObj: RegExp = /[a-z]/;
数组
定义
在 TypeScript 中,数组类型有多种定义方式。
1) 方括号表示法:
let numArr: number[] = [1, 2, 3];
let strArr: string[] = ['1', '2', '3'];
let nsArr: (number | string)[] = [1, '2', 3]; // 结合联合类型的数组表示法
let anyArr: any[] = [1, '2', true]; // 更常见的是结合any
console.log(numArr, strArr, nsArr, anyArr);
2) 数组泛型表示法:
let numGenericArr: Array<number> = [2, 3, 4];
console.log(numGenericArr);
3) 接口表示法:
interface NumberArr {
[index: number]: number;
}
let numInterfaceArr: NumberArr = [3, 4, 5];
console.log(numInterfaceArr);
遍历与枚举
遍历数组使用 forEach、map 等方法,用法与 ES6 的一样,如:
let strAry: string[] = ['A', 'B', 'C'];
str.forEach(function(item, index) {
console.log(`${index} : ${item}`);
});
enum 类型用于枚举数组,可以为一组数组赋予友好的名字:
enum Color { Red = 1, Green, Blue };
let colorName: string = Color[2];
let colorIndex: Color = Color.Green;
console.log(colorIndex, colorName); // 2 "Green"
引入第三方库
可以在 http://microsoft.github.io/TypeSearch/ 上查找想要安装的 TypeScript 版本的模块,以引入 jQuery 为例,首先使用 npm 安装模块,语句如: npm install --save-dev @types/jquery
。接着就可以在 TypeScript 中使用 jQuery 了。