# TypeScript入门
# 什么是TypeScript?
TypeScript是JavaScript的一个超集,提供了类型系统和对ES6的支持,它可以编译成纯JavaScript。 TypeScript由Microsoft开发且开源。
# 为什么选择TypeScript?
1、增加了代码的可读性和可维护性
类型系统实际上是最好的文档,大部分的函数看看类型的定义就可以知道如何使用了
可以在编译阶段就发现大部分错误,这总比在运行时候出错好
增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等
2、TypeScript非常包容
TypeScript 是 JavaScript 的超集,.js 文件可以直接重命名为 .ts 即可
即使不显式的定义类型,也能够自动做出类型推论
可以定义从简单到复杂的几乎一切类型
即使 TypeScript 编译报错,也可以生成 JavaScript 文件
兼容第三方库,即使第三方库不是用 TypeScript 写的,也可以编写单独的类型文件供 TypeScript 读取
3、拥有活跃的社区
# 使用TypeScript
npm install -g typescript //安装TypeScript
tsc hello.ts //编译TypeScript文件,这时候会生成一个编译好的文件hello.js
2
TypeScript 中,使用 : 指定变量的类型,: 的前后有没有空格都可以。
function sayHello(person: string) {
return 'Hello, ' + person;
}
let user = 'Tom';
console.log(sayHello(user));
2
3
4
5
6
上述例子中,我们用 : 指定 person 参数类型为 string。let是ES6中的关键字,和var类似,用于定义一个局部变量,
所声明的变量,只在let命令所在的代码块内有效。据此,for循环的计数器,就很合适使用let命令。另外,let所声明的变量一定要在声明后使用,否则报错。
# 原始数据类型
JavaScript 的类型分为两种:原始数据类型和对象类型。
原始数据类型包括:布尔值、数值、字符串、null、undefined 以及 ES6 中的新类型 Symbol。
# 在 TypeScript 中,使用 boolean 定义布尔值类型:
let isDone: boolean = false;
注意,使用构造函数 Boolean 创造的对象不是布尔值,而是一个Boolean对象:
let createdByNewBoolean: Boolean = new Boolean(1);
直接调用 Boolean 也可以返回一个 boolean 类型:
let createdByBoolean: boolean = Boolean(1);
在 TypeScript 中,boolean 是 JavaScript 中的基本类型,而 Boolean 是 JavaScript 中的构造函数。
其他基本类型(除了 null 和 undefined)一样,不再赘述。
# 数值
使用 number 定义数值类型:
let decLiteral: number = 6;
# 字符串
使用 string 定义字符串类型:
let myName: string = 'Tom';
let myAge: number = 25;
// 模板字符串
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;
2
3
4
5
6
其中用来定义ES6中的模板字符串(ES6 引入了模板字符串,用反引号
标识,它可以当作普通字符串使用,
也可以用来定义多行字符串,或者在字符串中嵌入变量),${expr} 用来在模板字符串中嵌入表达式。
# 空值
JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数:
function alertName(): void {
alert('My name is Tom');
}
2
3
# Null 和 Undefined
在 TypeScript 中,可以使用 null 和 undefined 来定义这两个原始数据类型:
let u: undefined = undefined;
let n: null = null;
2
undefined 类型的变量只能被赋值为 undefined,null 类型的变量只能被赋值为 null
# 任意值类型
any 类型允许被赋值为任意类型。如果是一个普通类型,在赋值过程中改变类型是不被允许的。
let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;
2
在任意值上访问任何属性都是允许的:
let anyThing: any = 'hello';
console.log(anyThing.myName);
console.log(anyThing.myName.firstName);
2
3
也允许调用任何方法:
let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');
2
3
4
可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。 变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:
let something;
something = 'seven';
something = 7;
something.setName('Tom');
2
3
4
5
等价于
let something: any;
something = 'seven';
something = 7;
something.setName('Tom');
2
3
4
5
# 类型推论
以下代码虽然没有指定类型,但是会在编译的时候报错:
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
2
事实上,它等价于:
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;
2
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。 如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查。
# 联合类型
联合类型表示取值可以为多种类型中的一种。 联合类型使用 | 分隔每个类型。
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
2
3
这里的 let myFavoriteNumber: string | number 的含义是,允许 myFavoriteNumber 的类型是 string 或者 number,但是不能是其他类型。
# 对象的类型——接口
在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
2
3
4
5
6
7
8
9
上面的例子中,我们定义了一个接口 Person,接着定义了一个变量 tom,它的类型是 Person。这样,我们就约束了 tom 的形状必须和接口 Person 一致。(接口一般首字母大写)
# 可选属性
有时我们希望不要完全匹配一个形状,那么可以用可选属性:
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom'
};
2
3
4
5
6
7
8
可选属性的含义是该属性可以不存在。
# 数组的类型
在 TypeScript 中,数组类型有多种定义方式,比较灵活。 「类型 + 方括号」表示法 最简单的方法是使用「类型 + 方括号」来表示数组:
let fibonacci: number[] = [1, 1, 2, 3, 5];
数组泛型 泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
//也可以使用数组泛型Array<elemType>来表示数组:
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
2
接口也可以用来描述数组:
interface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
2
3
4
NumberArray 表示:只要 index 的类型是 number,那么值的类型必须是 number。
# 函数的类型
一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单:
function sum(x: number, y: number): number {
return x + y;
}
2
3
注意,输入多余的(或者少于要求的)参数,是不被允许的。 如果要我们现在写一个对函数表达式(Function Expression)的定义,可能会写成这样:
let mySum = function (x: number, y: number): number {
return x + y;
};
2
3
这是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 mySum 添加类型,则应该是这样:
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
2
3
注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>。 在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
在 ES6 中,=> 叫做箭头函数,ES6 允许使用“箭头”(=>)定义函数。以下为ES6箭头函数:
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
2
3
4
5
6
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
2
3
4
5
6
7
8
9
具体可见ES6 中的箭头函数
# 类型断言
类型断言可以用来手动指定一个值的类型。 语法
<类型>值
或
值 as 类型
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须用后一种。 有时候,我们需要在还不确定类型的时候就访问其中一个类型的属性或方法。此时可以使用类型断言:
function getLength(something: string | number): number {
if ((<string>something).length) {
return (<string>something).length;
} else {
return something.toString().length;
}
}
2
3
4
5
6
7
类型断言的用法如上,在需要断言的变量前加上 Type 即可。 类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的。