一. TypeScript是什么
- TypeScript是JavaScript类型的超集,扩展了 JavaScript 的语法;
- TypeScript 设计目标是开发大型应用,它能编译出纯净、简洁的JavaScript代码,可以运行在在任何浏览器、任何计算机和任何操作系统上,并且是开源的;
- TypeScript 通过类型注解提供编译时的静态类型检查,就能将调试从运行期提前到编码期,诸如类型检查、越界检查这样的功能才能真正发挥作用;
- TypeScript的开发体验远远超过以往纯JavaScript的开发体验,无需运行程序即可修复潜在bug;
- TypeScript支持未来的ES6甚至ES7。在TypeScript中,可以直接使用ES6的最新特性,在编译时它会自动编译到ES5。
二. TypeScript配置
- 安装好NodeJS后,以管理员身份运行终端,使用
npm -g install ts-node typescript
命令进行全局安装;
- 在VS Code中开发,安装
TSLint、TypeScript Hero、Bracket Pair Colorizer
等插件;
- 新建一个.ts后缀的文件,任意写一段JS代码,点击运行试试是否配置成功。
三. 变量声明
使用let
和const
新的声明方式来代替var
,并加上类型说明,且作用域为块级即以{}
为界。
const
是对let
的一个增强,它能阻止对一个变量再次赋值。
例如:
let lang: string = 'TypeScript';//如果省略类型说明,TS也可进行自动推断
lang = 1010;//error! 如果需要可以使用联合类型:let lang: number | string = 'TS';
let age: number = 89;
let age = 64;//error!
const pi: number = 3.14159;//pi以后不可改变,类似常量
pi = 3.14;//error!
四. 解构
将对象、数组中的元素拆分到指定变量中,以方便使用
//解构数组
let input = [89, 64, 2018, 10];
let [first, second] = input;//注意使用[]
console.log(first); // 89
console.log(second); // 64
let [one, ...others] = input; //...other表示将剩余的数组展开
console.log(...others); //64 2018 10
let newArr = [89, ...others, 18];
console.log(newArr); // [ 89, 64, 2018, 10, 18 ]
//解构对象
let o = {
a: "foo",
b: 12,
c: "bar"
};
let {a, b} = o;//注意使用{},且变量名需与对象中道属性名一致
console.log(a, b); //foo 12
五. 函数
TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用。
1. 使用完整函数类型定义
变量名:类型
function 函数名():返回值类型{}
//命名函数,有完整的参数和返回类型。可以不用,TS将自动进行类型推断但推荐使用!
function add(x: number, y: number): number {
return x + y;
}
//匿名函数
let myAdd = function(x: number, y: number): number { return x + y; };
console.log(myAdd(1, '2'));//error
console.log(myAdd(1));//error
console.log(typeof myAdd(1, 2));//number
2. 可选参数
JavaScript里,每个参数都是可选的,可传可不传;没传参的时候,它的值就是undefined。
在TypeScript里使用变量名?:
类型实现可选参数的功能。
例如,我们想让last name是可选的:
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
console.log(buildName("Bob")); // works correctly now
console.log(buildName("Bob", "Adams", "Sr.")); // error, too many parameters
console.log(buildName("Bob", "Adams")); // right
注意:可选参数必须放在必要参数后面!!
3. 默认参数
在TypeScript里,我们也可以为参数提供一个默认值,当用户没有传递这个参数或传递的值是undefined时,它们叫做有默认初始化值的参数。
修改上例,把last name的默认值设置为"Smith":
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
console.log(buildName("Bob")); // right, returns "Bob Smith"
console.log(buildName("Bob", undefined)); // right, returns "Bob Smith"
console.log(buildName("Bob", "Adams", "Sr.")); // error, too many parameters
console.log(buildName("Bob", "Adams")); // right
在所有必须参数后面的带默认初始化的参数都是可选的,与可选参数一样,在调用函数的时候可以省略。
注意:与可选参数不同的是,默认参数不需要放在必须参数后面。
4. 剩余参数
必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。
有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来, 在TypeScript里,你可以把所有参数收集到一个变量里。
function greeting(firstName: string, ...restName: string[]) {
return `Hello ${firstName} ${restName.join(' ')}!`;
}
console.log(greeting('Osama', 'bin', 'Muhammad', 'bin', 'Awad', 'bin', 'Laden'));
console.log(greeting('Laden'));
//剩余参数,会被当做个数不限的可选参数。可以一个都没有,也可以有任意个
5. 箭头函数
JavaScript里,this
的值在函数被调用的时候才会指定。 这是个既强大又灵活的特点,但需要花时间弄清楚函数调用的上下文是什么,这不是一件很简单的事,尤其是在返回一个函数或将函数当做参数传递的时候。
为了解决这个问题,我们在函数被返回时就绑好正确的this。而箭头函数就能保存函数创建时的this值,而不是调用时的值。
//无参数,函数体代码只有一行,则该行结果即为函数返回值
let greeting1 = () => `Hello TS!`;
console.log(greeting1()); // Hello TS!
//一个参数,函数体代码只有一行,则该行结果即为函数返回值
let greeting2 = (name: string) => `Hello ${name}`;
console.log(greeting2('Kitty')); // Hello Kitty
//两个及以上的参数,函数体代码只有一行,则该行结果即为函数返回值
let add1 = (n1: number, n2: number) => n1 + n2;
console.log(add1(1, 2)); // 3
//两个及以上的参数,函数体代码多于一行,则必须用{}包裹,且显式给出return
let add2 = (n1: number, n2: number) => {
let sum = n1 + n2;
return sum;//改为sum++结果如何?
}
console.log(add2(1, 2)); // 3
六. 类Class
TypeScript 是面向对象的 JavaScript。
类描述了所创建的对象共同的属性和方法。
TypeScript 支持面向对象的所有特性,比如 类、接口等。
1. 类的定义和使用
//类的定义和使用
class MyInfo { //class是关键字,类名默认全部大写首字母
name: string; //属性
weather: string; //属性
constructor(name: string, weather: string){ //构造函数,一般用于初始化。如果没有,TS会自动生成一个,以备用new创建类实例时调用。
this.name = name;
this.weather = weather;
}
printInfo(): void { //其它函数,无返回值
console.log(`Hello, ${this.name}.`);
console.log(`Today is ${this.weather}.`);
}
}
let myData = new MyInfo('Jon', 'raining'); //使用new关键字生成对象,即该类的实例
myData.printInfo();
2. 类的属性和函数的访问权限
类中的属性和函数都有访问权限,默认为public
即全局可访问;protected
是在类的内部和其子类的内部可访问;private
只能在该类内部可访问。
//访问权限
class MyInfo {
public name: string; //public属性,可省略
private _weather: string; //私有属性,习惯以_开头进行命名
constructor(name: string, weather: string){ //构造函数,一般用于初始化
this.name = name;
this._weather = weather;
}
printInfo(): void { //其它函数
console.log(`Hello, ${this.name}.`);
console.log(`Today is ${this._weather}.`);
}
}
let myData = new MyInfo('Jon, 'raining'); //使用new关键字生成对象
console.log(myData._weather); //error!
myData.printInfo();
3. 存取器
TypeScript支持通过getter
和setter
来截取对对象成员的访问, 它能帮助你有效的控制对对象成员的访问。
当在类外部时,建议设置getter
和setter
操作其private属性
,即使public属性
也如此。
//getter和setter
class MyInfo {
private readonly _name: string; //私有属性,外部不可访问。readonly使其只能在初始化时赋值,以后不可更改。
private _weather: string; //私有属性
constructor(name: string, weather: string){ //构造函数,一般用于初始化
this._name = name;
this._weather = weather;
}
get name(): string {
return this._name;
}
set name(value: string) { //error! _name有readonly属性
this._name = value;
}
get weather(): string {
return this._weather;
}
set weather(value: string) {
this._weather = value;
}
}
let myData = new MyInfo('Jon', 'raining'); //使用new关键字生成对象
console.log(myData._name, myData._weather);
myData._weather = 'sunny'; //OK
myData._name = 'Wang'; //error!
console.log(myData);
readonly关键字将属性设置为只读的,只读属性必须在声明时或构造函数里被初始化。
只带有get不带有set的存取器自动被推断为readonly。
4. 静态属性
static
关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。
//静态属性,内建或自定义,无需new即可使用
console.log(Math.round(89.64)); //90
console.log(Math.pow(2, 8)); //256
class MyStaticClass {
static place = 'Earth';
static printInfo() {
console.log('We have only one Earth!');
}
}
console.log(MyStaticClass.place); //Earth
MyStaticClass.printInfo();
5. 继承
类继承使用关键字 extends
,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。
class Animal {
// 当构造函数传入的参数加上了“访问权限控制符”,则同时会声明同名类属性,并赋值
constructor(public name: string) { }
protected log(message: string) {
console.log(message);
}
move(distanceInMeters: number = 0) {
this.log(`${this.name} moved ${distanceInMeters}m.`);//请注意name来自何处
this.log('==============');
}
}
class Horse extends Animal {
constructor(name: string) {
super(name); // 通过super调用父类构造器
}
run(distanceInMeters = 50) { //自己独有的函数
this.log("Clop, clop...");
super.move(distanceInMeters); // 通过super调用父类方法
}
}
let tom: Horse = new Horse("Tommy");
tom.run(66);
执行结果为:
注意:TypeScript 一次只能继承一个类,不支持继承多个类,但TypeScript 支持多重继承(A 继承 B,B 继承 C)。
七. 模块Module
- 对于大型的项目,我们需要使用模块进行管理。每个
.ts
文件就是一个模块,通过 export
来对外部模块暴露元素,通过 import
来引入模块。
- 模块是自声明的;两个模块之间的关系是通过在文件级别上使用
imports
和exports
建立的。
语法格式如下:
// 文件名 : SomeInterface.ts
export interface SomeInterface {
// 代码部分
}
要在另外一个文件使用该模块就需要使用 import 关键字来导入:
import someInterfaceRef = require("./SomeInterface");
八. 总结
TypeScript的设计解决了JavaScript的问题,让程序模块化,利于我们开发大型程序。
总的来说TypeScript还是比较容易上手的,因为它只是在JavaScript上扩展了语法。且编辑器提供精准的语法提示,让我们更方便地实践面向对象的编程。
九. 学习资料
https://typescript.bootcss.com/