TypeScript是微软开发的开源编程语言,是JavaScript的超集并可以转译成纯的JavaScript,对React、Angular、Vue这三大框架都有非常友好的支持。
安装很方便快捷,官网首页非常显要地给出了两条命令,安装用
npm installl -g typescript
编译用
tsc helloworld.ts
会在相同的文件夹下生成同名的js
文件。需要注意一点的是,tsc
命令可以编辑多个ts文件。其实所谓编译,更像是代码转格式,即把typescript转换成JavaScript的格式。如果想从命令行输出的话,需要用到nodejs,输入node helloworld.js
。
既然是js的超集,那么数据类型当然不可能完全相同,而且声明变量时所用到的关键字也不尽相同。但二者也有相似之处,例如都没有整型。
js使用了动态类型,即如果不进行声明的话,那么变量的数据类型的可以随意更改的。对于未赋值变量,可以用new
来进行变量类型的声明。在ts中,同样可以实现可变的数据类型,但需要用关键字any
来进行修饰。
let myAge: number = 18;
var herAge = 15; //js的语句也可以识别
var hisAge = new Number; //js的语句也可以识别
const birth: number = 1999; //const声明不可变的变量
let myName: string = "test"; //单引号和双引号表示字符串
/*反引号可内嵌表达式,这个引号就是表示代码片的那个引号。。。 */
let worlds: string = `hello,I'm ${myName} and ${myAge} years old.`;
let flag: boolean= true;
let arr: number[] = [1,2,3]
let arr2: Array<number> = [2,3,4] //数组泛型
let cell: [string,number,boolean] = [myName, myAge, flag] //元组内部的元素不必相同
console.log(worlds)
在js中提供了Undefined
和Null
类型,前者表示未设置值的变量,后者表示空变量,二者可以赋值给任何类型,从而可用于抛出异常等场景。但是在ts中,这种跨类型的赋值是不允许的,如果一个变量可能会发生某些异常,需要在其声明的时候用|
将这两种类型绑定在数据上。
let x: number | null | undefined;
此外,ts还提供了never
类型,表示不会出现的值,对此我表示很困惑,等明白之后再补上吧。
条件语句主要有三种,if...else
,if...else if...else
,switch...case1...case2...
,很符合程序员的直觉。循环语句除了for
,for...in
之外,还有for...of
,forEach
,every
和some
等。
对于函数来说,由于在ts中对类型的要求比较严格,所以在传参的时候需要对数据类型进行声明。此外,提供了修饰符?
用于可选参数,并且支持默认参数,相比之下比js更加规范一些。
//ts代码
function add(x:number, y:number=12, z?:number):number{
if (z)
return x+y+z; //单行代码可以不用{},但对于python写习惯的人来说不建议这么做
else
z = 0;
return x+y;
}
console.log(add(1)); //由于y默认为12,所以输出为13
console.log(add(1,2)); //如果在声明时,z不加?会报错。
通过tsc
将其转成js文件如下。
function add(x, y, z) {
if (y === void 0) { y = 12; } //js中需要在函数中声明默认参数。
if (z)
return x + y + z;
else
z = 0;
return x + y;
}
console.log(add(1));
console.log(add(1, 2)); //此时z的值为undefined,故if(z)为false
typescript还支持剩余参数表达式
//ts代码,用...nums表示剩余的数量未知的参数
function muti(x:number,...nums:number[]){
var sum: number = x;
for(var i = 0; i<nums.length; i++)
sum *= nums[i] //在ts中其实可以不写分号,但一般建议写上
return sum;
}
console.log(muti(3)) //输出为3
console.log(muti(3,4,5)) //输出为60
转成js代码如下
function muti(x) {
var nums = [];
for (var _i = 1; _i < arguments.length; _i++) {
nums[_i - 1] = arguments[_i];//在js中,默认剩余参数为arguments
}
var sum = x;
for (var i = 0; i < nums.length; i++)
sum *= nums[i];
return sum;
}
console.log(muti(3));
console.log(muti(3, 4, 5));
所谓重载,就是对于同一函数名,当我们传入不同的参数时,执行不同的操作。在js中,我们可以通过自动判断类型来达到重载的目的。在ts中,我们可以事先精确地声明我们所定义的重载的函数,以起到类型检查的作用。
//ts程序,如果输入参数是数字,则相加;如果是字符串则合并
function add(...str:string[]):string;//重载函数1
function add(...num:number[]):number;//重载函数2
//此为函数重载的实现,并不能算作一个新的重载函数
function add(...para:any[]):any{
if(typeof para[0]==="string"){
let str:string = "";
para.forEach((val)=>{str = str+val});//forEach循环,参数val为para中的值
return str;
}
else{
let num = 0;
para.forEach((val)=>{num+=val});
return num;
}
}
console.log(add(1,2,3,4)); //输出为10
console.log(add('1','2','3','4')); //输出为'1234'
转成js代码如下
function add() {
var para = [];
for (var _i = 0; _i < arguments.length; _i++) {
para[_i] = arguments[_i];
}
if (typeof para[0] === "string") {
var str_1 = "";
para.forEach(function (val) { str_1 = str_1 + val; });
return str_1;
}
else {
var num_1 = 0;
para.forEach(function (val) { num_1 += val; });
return num_1;
}
}
console.log(add(1, 2, 3, 4));
console.log(add('1', '2', '3', '4'));
可见ts中对重载函数的声明并未体现在js代码中,但是在ts文件中,输入console.log(add(1, 2, 3, '4'));
编译器会自动检查出错误,而js并不会。或者将ts中最上面的两行声明代码注释掉,也不会检查出问题。
在javascript中有一种数据类型就叫做对象,然而typescript号称面向对象的javascript,所以事情似乎不这么简单。
相对来说,js中的对象类似于一组键值对的组合,其值既可以为属性,也可以为方法。在早期的时候似乎并没有加入继承这类面向对象的基本特征,而且直到现在也没有多态。而ts的面向对象,则是引入了类这种面向对象中常用的类型。
在typescript中定义一个类还是比较符合程序员的直觉的。
class Person{
//构造函数,可以省略
constructor(name:string,littleName:string){
this.name = name;
this.littleName = littleName;
}
public name: string; //访问不受限制,默认修饰符
private littleName: string; //private字段不能被外部访问
//protected可以在派生类中被访问
protected myLittleName(){console.log(this.littleName);}
public printMyName(){console.log(this.name);}
}
//类的继承用extends
class Chinese extends Person{
public myName()
{
this.printMyName();
this.myLittleName(); //protected字段可以被派生类访问
/*但是不能访问littleName
console.log(this.littleName)会报错*/
}
}
let a = new Person("Tony","铁蛋");
a.printMyName(); //输出为Tony
let b = new Chinese("Tony","铁蛋");
b.myName(); //输出为Tony,铁蛋
转成js的代码
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Person = /** @class */ (function () {
//构造函数,可以省略
function Person(name, littleName) {
this.name = name;
this.littleName = littleName;
}
//protected可以在派生类中被访问
Person.prototype.myLittleName = function () { console.log(this.littleName); };
Person.prototype.printMyName = function () { console.log(this.name); };
return Person;
}());
var Chinese = /** @class */ (function (_super) {
__extends(Chinese, _super);
function Chinese() {
return _super !== null && _super.apply(this, arguments) || this;
}
Chinese.prototype.myName = function () {
this.printMyName();
this.myLittleName();
};
return Chinese;
}(Person));
var a = new Person("Tony", "铁蛋");
a.printMyName();
var b = new Chinese("Tony", "铁蛋");
b.myName();