TypeScript学习
TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持
好处:
- 在编译阶段就发现大部分错误,增加了代码的可读性和可维护性
- 可以定义从简单到复杂的几乎一切类型,TypeScript 编译报错,也可以生成 JavaScript 文件
缺点:
- 需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师可能不是很熟悉的概念
- 短期可能会增加一些开发成本,毕竟要多写一些类型的定义,不过对于一个需要长期维护的项目,TypeScript 能够减少其维护成本
- 集成到构建流程需要一些工作量
安装:
如果报错:
npm ERR! code UNABLE_TO_GET_ISSUER_CERT_LOCALLY
npm ERR! errno UNABLE_TO_GET_ISSUER_CERT_LOCALLY
执行npm config set strict-ssl false (关闭npm的https) 即可
ps:我们约定使用 TypeScript 编写的文件以 .ts 为后缀,用 TypeScript 编写 React 时,以 .tsx 为后缀。
基础:
TypeScript 中,使用 : 指定变量的类型,: 的前后有没有空格都可以。
function sayHello(person: string) {
return 'Hello, ' + person;
}
let decLiteral: number = 6;
其中 ` 用来定义 ES6 中的模板字符串,${expr} 用来在模板字符串中嵌入表达式。
let sentence: string = `Hello, my name is ${myName}.I'll be ${myAge + 1} years old next month.`
特点:
1\JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数:
function alertName(): void {
alert('My name is Tom');
}
let unusable: void = undefined;
2\任意值(Any)用来表示允许赋值为任意类型。如果是一个普通类型,在赋值过程中改变类型是不被允许的,而any可以.
3\联合类型使用 | 分隔每个类型。let myFavoriteNumber: string | number;
**4\对象类型**在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。
interface Person {//定义接口 Person
name: string;
age: number;
}
let tom: Person = {//定义了变量 tom,类型是 Person,tom的形状和 Person一致并不允许少或者多属性
name: 'Tom',
age: 25
};
**可选属性和任意属性**
interface Person {//使用?是可选属性,只能少,不能多.,使用 [propName: string] 定义了任意属性取 string 类型的值。
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
ps:需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集,
即,使用了propName 那么age一旦存在,就不能用age:25
只读属性
interface Person {//只能在创建的时候被赋值,其余时间不能赋值.
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
5\数组类型
let fibonacci: (number | string)[] = [1, 1, '2', 3, 5];
**也可以使用数组泛型(Array Generic) Array<elemType> 来表示数组:**
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
用接口也可以描述数组
interface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
只要 index 的类型是 number,那么值的类型必须是 number
**any 表示数组中允许出现任意类型**
let list: any[] = ['Xcat Liu', 25, { website: 'http://xcatliu.com' }];
6\函数
TypeScript需要把输入和输出都考虑到.PS:输入多余的或者少于的参数是不被允许的.
function sum(x: number, y: number): number {
return x + y;
}
在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
**用接口的形式定义函数**
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
**可选参数**
同样用?,跟在冒号前面. 可选参数必须接在必需参数后面
**参数默认值**
TypeScript 会将添加了默认值的参数识别为可选参数,此时就不受「可选参数必须接在必需参数后面」
function buildName(firstName: string = 'Tom', lastName: string) {
return firstName + ' ' + lastName;
}
**剩余参数**
ES6 中,可以使用 ...rest 的方式获取函数中的剩余参数(rest 参数),rest 参数只能是最后一个参数
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
**重载**
允许一个函数接受不同数量或类型的参数时,作出不同的处理。以下可以做到:输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串。
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
重复定义了多次函数 reverse,前几次都是函数定义,最后一次是函数实现
TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。
7\类型断言:在需要断言的变量前加上 <Type> 即可。
<类型>值
或
值 as 类型(tsx中,即react中)
function getLength(something: string | number): number {
if ((<string>something).length) {//类型断言,将something断言为string
return (<string>something).length;
} else {
return something.toString().length;
}
}
声明文件
需要使用 declare var 来定义它的类型:
已经引入了jq不行,还需要声明 declare var : ( s e l e c t o r : s t r i n g ) = > a n y ; 才 能 够 使 用 : (selector: string) => any; 才能够使用 :(selector:string)=>any;才能够使用(’#foo’);
declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型
声明语句放到一个单独的文件(jQuery.d.ts)中,声明文件必需以 .d.ts 为后缀。
\\
其实可以用@types 统一管理第三方库的声明文件。
@types 的使用方式很简单,直接用 npm 安装对应的声明模块即可
npm install @types/jquery --save-dev
//
如果是以 npm install @types/xxx --save-dev 安装的,则不需要任何配置
全局变量的声明文件主要有以下几种语法:
declare var 声明全局变量,一般来说,全局变量都是禁止修改的常量,都应该使用 const 而不是 var 或 let。
declare function 声明全局方法,用来定义全局函数的类型。
jQuery 其实就是一个函数,所以也可以用 function 来定义 declare function jQuery(selector: string): any;
在声明语句中,重载也是支持的
declare function jQuery(selector: string): any;
declare function jQuery(domReadyCallback: () => any): any;
jQuery('#foo');
jQuery(function() {
alert('Dom Ready!');
});
declare class 声明全局类,当全局变量是一个类的时候,我们用 declare class 来定义它的类型:
declare class Animal {
constructor(name: string);
sayHi(): string;
}
let cat = new Animal('Tom');
declare class 语句也只能用来定义类型,不能用来定义具体的值,定义 sayHi 方法的具体实现则会报错:
declare class Animal {
constructor(name: string);
sayHi() {
return `My name is ${this.name}`;
};
// ERROR: An implementation cannot be declared in ambient contexts.
}
declare enum 声明全局枚举类型
declare namespace 声明全局对象(含有子属性)
interface 和 type 声明全局类型