TypeScript is a syntactic sugar for JavaScript. TypeScript syntax is a superset of ECMAScript 2015 (ES2015) syntax. Every JavaScript program is also a TypeScript program.
语言层面:JavaScript和TypeScript都是ECMAScript(ECMA-262)的具体实现。
执行环境层面:浏览器引擎和Node.js都能够直接运行JavaScript,但无法直接运行TypeScript。
时序层面:TypeScript被真正执行前,会通过编译转换生成JavaScript,之后才能被解释执行。
厂商层面:JavaScript由Netscape率先推出,现在主要由各大浏览器厂商实现。而TypeScript is a trademark of Microsoft Corporation,目前由微软进行设计和维护。
TypeScript是ECMAScript 2015的语法超集,是JavaScript的语法糖。JavaScript程序可以直接移植到TypeScript,TypeScript需要编译(语法转换)生成JavaScript才能被浏览器执行。
1、any 任意类型
2、number 数字类型 双精度 64 位浮点值。它可以用来表示整数和分数。
let binaryLiteral: number = 0b1010; // 二进制
let octalLiteral: number = 0o744; // 八进制
let decLiteral: number = 6; // 十进制
let hexLiteral: number = 0xf00d; // 十六进制
3、string 一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式
let name: string = "mobanw";
let years: number = 5;
let words: string = `您好,今年是 ${ name } 发布 ${ years + 1} 周年`;
4、boolean 布尔类型 true/false
5、数组类型
// 在元素类型后面加上[]
let arr: number[] = [1, 2];
// 或者使用数组泛型
let arr: Array = [1, 2];
6、元组 元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同
let x: [string, number];
x = ['mobanw', 1]; // 运行正常
x = [1, 'mobanw']; // 报错
console.log(x[0]); // 输出 mobanw
7、enum 枚举类型用于定义数值集合
enum Color {Red, Green, Blue};
let c: Color = Color.Blue;
console.log(c); // 输出 2
8、void 用于标识方法返回值的类型,表示该方法没有返回值
function hello(): void {
alert("hello mobanw");
}
9、null 表示对象值缺失
10、undefined 用于初始化变量为一个未定义的值
11、never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值
注意:TypeScript 和 JavaScript 没有整数类型。
Null 和 Undefined 是其他任何类型(包括 void)的子类型,可以赋值给其它类型,如数字类型,此时,赋值后的类型会变成 null 或 undefined。而在TypeScript中启用严格的空校验(–strictNullChecks)特性,就可以使得null 和 undefined 只能被赋值给 void 或本身对应的类型,示例代码如下:
// 启用 --strictNullChecks
let x: number;
x = 1; // 运行正确
x = undefined; // 运行错误
x = null; // 运行错误
如果一个类型可能出现 null 或 undefined, 可以用 | 来支持多种类型,示例代码如下:
// 启用 --strictNullChecks
let x: number | null | undefined;
x = 1; // 运行正确
x = undefined; // 运行正确
x = null; // 运行正确
never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环),示例代码如下:
let x: never;
let y: number;
// 运行错误,数字类型不能转为 never 类型
x = 123;
// 运行正确,never 类型可以赋值给 never类型
x = (()=>{ throw new Error('exception')})();
// 运行正确,never 类型可以赋值给 数字类型
y = (()=>{ throw new Error('exception')})();
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到的终止点的情况
function loop(): never {
while (true) {}
}
变量的命名规则:_、$, 不能以数字开头
包含字母、数字、
声名变量及初始值:
var uname:string = "mobanw";
声明变量并初始值,但不设置类型,该变量可以是任意类型:
var uname = "mobanw";
声明变量没有设置类型和初始值,类型可以是任意类型,默认初始值为 undefined:
var uname;
注意:变量不要使用 name 否则会与 DOM 中的全局 window 对象下的 name 属性出现了重名。
TypeScript 遵循强类型,如果将不同的类型赋值给变量会编译错误
类型断言(类型转换)
<类型>值 或 值 as 类型
var str = '1'
var str2:number = str //str、str2 是 string 类型
console.log(str2)
类型推断
如果由于缺乏声明而不能推断出类型,那么它的类型被视作默认的动态 any 类型。
var num = 2; // 类型推断为 number
console.log("num 变量的值为 "+num);
num = "12"; // 编译错误
console.log(num);
变量作用域
有以下几种作用域:
全局作用域:
在代码任何位置使用
类作用域:
这个变量也可以称为 字段。类变量声明在一个类里头,但在类的方法外面。 该变量可以通过类的对象来访问。类变量也可以是静态的,静态的变量可以通过类名直接访问
局部作用域:
局部变量,局部变量只能在声明它的一个代码块(如:方法)中使用
var global_num = 12 // 全局变量
class Numbers {
num_val = 13; // 实例变量
static sval = 10; // 静态变量
storeNum():void {
var local_num = 14; // 局部变量
}
}
console.log("全局变量为: "+global_num)
console.log(Numbers.sval) // 静态变量
var obj = new Numbers();
console.log("实例变量: "+obj.num_val)
+、 -、 *、 /、 %、 ++、 –
&&、 ||、 !
==、 !=、 >、 <、 >=、 <=
按位运算符
|运算符|描述|例子|类似于|结果|十进制|
|–|–|–|–|–|–|
|&|AND,按位与处理两个长度相同的二进制数,两个相应的二进位都为 1,该位的结果值才为 1,否则为 0。|x = 5 & 1|0101 & 0001|0001|1|
|||OR,按位或处理两个长度相同的二进制数,两个相应的二进位中只要有一个为 1,该位的结果值为 1。|x = 5 | 1|0101 | 0001|0101|5|
|~|取反,取反是一元运算符,对一个二进制数的每一位执行逻辑反操作。使数字 1 成为 0,0 成为 1。|x = ~ 5|~0101|1010|-6|
|^|异或,按位异或运算,对等长二进制模式按位或二进制数的每一位执行逻辑异按位或操作。操作的结果是如果某位不同则该位为 1,否则该位为 0。|x = 5 ^ 1|0101 ^ 0001|0100|4|
|<<|左移,把 << 左边的运算数的各二进位全部左移若干位,由 << 右边的数指定移动的位数,高位丢弃,低位补 0。|x = 5 << 1|0101 << 1|1010|10|
|>>|右移,把 >> 左边的运算数的各二进位全部右移若干位,>> 右边的数指定移动的位数。|x = 5 >> 1|0101 >> 1|0010|2|
|>>>|无符号右移,与有符号右移位类似,除了左边一律使用0 补位。|x = 2 >>> 1|0010 >>> 1|0001|1|
赋值运算符
=、 +=、 -=、 *=、 /=、
var num:number = -2
var result = num > 0 ? "大于 0" : "小于 0,或等于 0"
console.log(result)
var msg:string = "Mobanw"+".COM"
console.log(msg)
var num = 12
console.log(typeof num); //输出结果: number
if、 if…else、 if…else if…else、 switch
for…in、 for…of 、forEach、 while、do…while、every 和 some 循环
var j:any;
var n:any = "a b c"
for(j in n) {
console.log(n[j])
}
let someArray = [1, "string", false];
for (let entry of someArray) {
console.log(entry); // 1, "string", false
}
let list = [4, 5, 6];
list.forEach((val, idx, array) => {
// val: 当前值
// idx:当前index
// array: Array
});
let list = [4, 5, 6];
list.every((val, idx, array) => {
// val: 当前值
// idx:当前index
// array: Array
return true; // Continues
// Return false will quit the iteration
});
// 函数定义
function greet():string { // 返回一个字符串
return "Hello World"
}
function caller() {
var msg = greet() // 调用 greet() 函数
console.log(msg)
}
// 调用函数
caller()
带参数的函数:
function add(x: number, y: number): number {
return x + y;
}
console.log(add(1,2))
可选参数:
如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选,可选参数使用问号标识 ?。
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // 错误,缺少参数
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // 正确
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
默认参数:
function calculate_discount(price:number,rate:number = 0.50) {
var discount = price * rate;
console.log("计算结果: ",discount);
}
calculate_discount(1000)
calculate_discount(1000,0.30)
剩余参数:
function addNumbers(...nums:number[]) {
var i;
var sum:number = 0;
for(i = 0;i
匿名函数:
var res = function(a:number,b:number) {
return a*b;
};
console.log(res(12,2))
匿名函数自调用
(function () {
var x = "Hello!!";
console.log(x)
})()
构造函数
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
console.log(x);
递归函数
function factorial(number) {
if (number <= 0) { // 停止执行
return 1;
} else {
return (number * factorial(number - 1)); // 调用自身
}
};
console.log(factorial(6)); // 输出 720
Lambda 函数(箭头函数)
var foo = (x:number)=>10 + x
console.log(foo(100)) //输出结果为 110
我们可以不指定函数的参数类型,通过函数内来推断参数类型:
var func = (x)=> {
if(typeof x=="number") {
console.log(x+" 是一个数字")
} else if(typeof x=="string") {
console.log(x+" 是一个字符串")
}
}
func(12)
func("Tom")
单个参数 () 是可选的,省略括号:
var display = x => {
console.log("输出为 "+x)
}
display(12)
无参数时可以设置空括号:
var disp =()=> {
console.log("Function invoked");
}
disp();
函数重载:
重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
function disp(s1:string):void;
function disp(n1:number,s1:string):void;
function disp(x:any,y?:any):void {
console.log(x);
console.log(y);
}
disp("abc")
disp(1,"xyz");
var num = new Number(value);
注意: 如果一个参数值不能转换为一个数字将返回 NaN (非数字值)。
console.log("TypeScript Number 属性: ");
console.log("最大值为: " + Number.MAX_VALUE);
console.log("最小值为: " + Number.MIN_VALUE);
console.log("负无穷大: " + Number.NEGATIVE_INFINITY);
console.log("正无穷大:" + Number.POSITIVE_INFINITY);
prototype 实例
function employee(id:number,name:string) {
this.id = id
this.name = name
}
var emp = new employee(123,"admin")
employee.prototype.email = "[email protected]"
console.log("员工号: "+emp.id)
console.log("员工姓名: "+emp.name)
console.log("员工邮箱: "+emp.email)
Number 对象方法
toExponential() 把对象的值转换为指数计数法。
toFixed() 把数字转换为字符串,并对小数点指定位数
toLocaleString() 把数字转换为字符串,使用本地数字格式顺序。
toPrecision() 把数字格式化为指定的长度。
var num = new Number(7.123456);
console.log(num.toPrecision()); // 输出:7.123456
console.log(num.toPrecision(1)); // 输出:7
console.log(num.toPrecision(2)); // 输出:7.1
toString() 把数字转换为字符串,使用指定的基数。数字的基数是 2 ~ 36 之间的整数。若省略该参数,则使用基数 10。
var num = new Number(10);
console.log(num.toString()); // 输出10进制:10
console.log(num.toString(2)); // 输出2进制:1010
console.log(num.toString(8)); // 输出8进制:12
valueOf()返回一个 Number 对象的原始数字值。
var num = new Number(10);
console.log(num.valueOf()); // 输出:10
var txt = new String("string");
或者更简单方式:
var txt = "string";
constructor 对创建该对象的函数的引用。
var str = new String( "This is string" );
console.log("str.constructor is:" + str.constructor)
//输出结果:
str.constructor is:function String() { [native code] }
length 返回字符串的长度。
prototype 允许您向对象添加属性和方法。
function employee(id:number,name:string) {
this.id = id
this.name = name
}
var emp = new employee(123,"admin")
employee.prototype.email="[email protected]" // 添加属性 email
console.log("员工号: "+emp.id)
console.log("员工姓名: "+emp.name)
console.log("员工邮箱: "+emp.email)
charAt() 返回在指定位置的字符。
var str = new String("MOBANW");
// var str = "MOBANW";
console.log("str.charAt(0) 为:" + str.charAt(0)); // M
console.log("str.charAt(1) 为:" + str.charAt(1)); // O
console.log("str.charAt(2) 为:" + str.charAt(2)); // B
charCodeAt() 返回在指定的位置的字符的 Unicode 编码。
var str = "MOBANW";
console.log("str.charCodeAt(0) 为:" + str.charCodeAt(0)); // 77
console.log("str.charCodeAt(1) 为:" + str.charCodeAt(1)); // 79
console.log("str.charCodeAt(2) 为:" + str.charCodeAt(2)); // 66
concat() 连接两个或更多字符串,并返回新的字符串。
var str1 = new String( "MOBANW" );
var str2 = new String( "GOOGLE" );
var str3 = str1.concat( str2 );
console.log("str1 + str2 : "+str3) // MOBANWGOOGLE
indexOf() 返回某个指定的字符串值在字符串中首次出现的位置。
lastIndexOf() 从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。
localeCompare() 用本地特定的顺序来比较两个字符串。
返回值大于0:说明当前字符串string大于对比字符串targetString
返回值小于0:说明当前字符串string小于对比字符串targetString
返回值等于0:说明当前字符串string等于对比字符串targetString
var str1 = new String( "This is beautiful string" );
var index1 = str1.localeCompare( "This is beautiful string");
var index2 = str1.localeCompare( "This is batter string");
var index3 = str1.localeCompare( "This is good string");
console.log("localeCompare first :" + index1 ); // 0
console.log("localeCompare first :" + index2 ); // 1
console.log("localeCompare first :" + index3 ); // -1
var str = 'aaa',
strCom = 'bbb',
strCom2 = 'aaa';
str.localeCompare(strCom); //-1
strCom.localeCompare(str); //1
str.localeCompare(strCom2); //0
match() 查找找到一个或多个正则表达式的匹配。
var str="The rain in SPAIN stays mainly in the plain";
var n=str.match(/ain/g); // ['ain', 'ain', 'ain']
replace() 替换与正则表达式匹配的子串
var re = /(\w+)\s(\w+)/;
var str = "zara ali";
var newstr = str.replace(re, "$2, $1");
console.log(newstr); // ali, zara
search() 检索与正则表达式相匹配的值
slice() 提取字符串的片断,并在新的字符串中返回被提取的部分。
var str="Hello happy world!"
document.write(str.slice(6))
split() 把字符串分割为子字符串数组。
substr(start, length) 从起始索引号提取字符串中指定数目的字符。
substring(start,stop) 提取字符串中两个指定的索引号之间的字符。
toLocaleLowerCase() 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射。
toLocaleUpperCase() 据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射。
toLowerCase() 转小写
toUpperCase() 转大写
toString() 返回字符串
valueOf() 返回指定字符串对象的原始值
var sites:string[];
sites = ["Google","Mobanw","Taobao"]
// sites:string[] = ["Google","Mobanw","Taobao"]
console.log(sites[0]); //Google
console.log(sites[1]); //Mobanw
Array 对象
var arr_names:number[] = new Array(4)
for(var i = 0; i
数组解构
var arr:number[] = [12,13]
var[x,y] = arr // 将数组的两个元素赋值给变量 x 和 y
console.log(x) //12
console.log(y) //13
数组迭代
var j:any;
var nums:number[] = [1001,1002,1003,1004]
for(j in nums) {
console.log(nums[j])
}
多维数组
var multi:number[][] = [[1,2,3],[23,24,25]]
console.log(multi[0][0])
console.log(multi[0][1])
console.log(multi[0][2])
console.log(multi[1][0])
console.log(multi[1][1])
console.log(multi[1][2])
数组在函数中的使用
作为参数传递给函数
var sites:string[] = new Array("Google","Mobanw","Taobao","Facebook")
function disp(arr_sites:string[]) {
for(var i = 0;i
作为函数的返回值
function disp():string[] {
return new Array("Google", "Mobanw", "Taobao", "Facebook");
}
var sites:string[] = disp()
for(var i in sites) {
console.log(sites[i])
}
数组方法
concat() 连接两个或更多的数组,并返回结果。
every() 检测数值元素的每个元素是否都符合条件。
function isBigEnough(element, index, array) {
return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
console.log("Test Value : " + passed ); // false
filter() 检测数值元素,并返回符合条件所有元素的数组。
function isBigEnough(element, index, array) {
return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].filter(isBigEnough);
console.log("Test Value : " + passed ); // 12,130,44
forEach() 数组每个元素都执行一次回调函数。
let num = [7, 8, 9];
num.forEach(function (value) {
console.log(value);
});
indexOf() 搜索数组中的元素,并返回它所在的位置。如果搜索不到,返回值 -1,代表没有此项。
join() 把数组的所有元素放入一个字符串。
lastIndexOf() 返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
map() 通过指定函数处理数组的每个元素,并返回处理后的数组。
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
console.log("roots is : " + roots ); // 1,2,3
pop() 删除数组的最后一个元素并返回删除的元素。
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
reduce() 将数组元素计算为一个值(从左到右)。
var total = [0, 1, 2, 3].reduceRight(function(a, b){ return a + b; });
console.log("total is : " + total ); // 6
reverse() 反转数组的元素顺序返回一个字符串。
shift() 删除数组并返回数组的第一个元素。
slice(start, stop) 选取数组的的一部分,并返回一个新数组。
some() 检测数组元素中是否有元素符合指定条件。
function isBigEnough(element, index, array) {
return (element >= 10);
}
var retval = [2, 5, 8, 1, 4].some(isBigEnough);
console.log("Returned value is : " + retval ); // false
var retval = [12, 5, 8, 1, 4].some(isBigEnough);
console.log("Returned value is : " + retval ); // tru
sort() 对数组的元素进行排序。
splice(start, removeLength, addStr) 从数组中添加或删除元素。
var arr = ["orange", "mango", "banana", "sugar", "tea"];
var removed = arr.splice(2, 0, "water");
console.log("After adding 1: " + arr ); // orange,mango,water,banana,sugar,tea
console.log("removed is: " + removed);
removed = arr.splice(3, 1);
console.log("After removing 1: " + arr ); // orange,mango,water,sugar,tea
console.log("removed is: " + removed); // banana
toString() 把数组转换为字符串,并返回结果。
unshift() 向数组的开头添加一个或更新元素,并返回新的长度。
var arr = new Array("orange", "mango", "banana", "sugar");
var length = arr.unshift("water");
console.log("Returned array is : " + arr ); // water,orange,mango,banana,sugar
console.log("Length of the array is : " + length ); // 5
map.clear() – 移除 Map 对象的所有键/值对 。
map.set() – 设置键值对,返回该 Map 对象。
map.get() – 返回键对应的值,如果不存在,则返回 undefined。
map.has() – 返回一个布尔值,用于判断 Map 中是否包含键对应的值。
map.delete() – 删除 Map 中的元素,删除成功返回 true,失败返回 false。
map.size – 返回 Map 对象键/值对的数量。
map.keys() - 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。
map.values() – 返回一个新的Iterator对象,包含了Map对象中每个元素的值 。
let nameSiteMapping = new Map();
// 设置 Map 对象
nameSiteMapping.set("Google", 1);
nameSiteMapping.set("Mobanw", 2);
nameSiteMapping.set("Taobao", 3);
// 获取键对应的值
console.log(nameSiteMapping.get("Mobanw")); // 2
// 判断 Map 中是否包含键对应的值
console.log(nameSiteMapping.has("Taobao")); // true
console.log(nameSiteMapping.has("Zhihu")); // false
// 返回 Map 对象键/值对的数量
console.log(nameSiteMapping.size); // 3
// 删除 Mobanw
console.log(nameSiteMapping.delete("Mobanw")); // true
console.log(nameSiteMapping);
// 移除 Map 对象的所有键/值对
nameSiteMapping.clear(); // 清除 Map
console.log(nameSiteMapping);
使用 es6 编译:
tsc --target es6 test.ts
迭代 Map
let nameSiteMapping = new Map();
nameSiteMapping.set("Google", 1);
nameSiteMapping.set("Mobanw", 2);
nameSiteMapping.set("Taobao", 3);
// 迭代 Map 中的 key
for (let key of nameSiteMapping.keys()) {
console.log(key);
}
// 迭代 Map 中的 value
for (let value of nameSiteMapping.values()) {
console.log(value);
}
// 迭代 Map 中的 key => value
for (let entry of nameSiteMapping.entries()) {
console.log(entry[0], entry[1]);
}
// 使用对象解析
for (let [key, value] of nameSiteMapping) {
console.log(key, value);
}
tsc --target es6 test.ts
var mytuple = [10,"Mobanw"]; // 创建元组
console.log(mytuple[0])
console.log(mytuple[1])
元组运算
push() 向元组添加元素,添加在最后面。
pop() 从元组中移除元素(最后一个),并返回移除的元素。
var mytuple = [10,"Hello","World","typeScript"];
console.log("添加前元素个数:"+mytuple.length) // 返回元组的大小
mytuple.push(12) // 添加到元组中
console.log("添加后元素个数:"+mytuple.length)
console.log("删除前元素个数:"+mytuple.length)
console.log(mytuple.pop()+" 元素从元组中删除") // 删除并返回删除的元素
console.log("删除后元素个数:"+mytuple.length)
更新元组
var mytuple = [10, "Mobanw", "Taobao", "Google"]; // 创建一个元组
console.log("元组的第一个元素为:" + mytuple[0])
// 更新元组元素
mytuple[0] = 121
console.log("元组中的第一个元素更新为:"+ mytuple[0])
解构元组
var a =[10,"Mobanw"]
var [b,c] = a
console.log( b )
console.log( c )
联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。
注意:只能赋值指定的类型,如果赋值其它类型就会报错
var val:string|number
val = 12
console.log("数字为 "+ val)
val = "Mobanw"
console.log("字符串为 " + val)
如果赋值其它类型就会报错
也可以将联合类型作为函数参数使用:
function disp(name:string|string[]) {
if(typeof name == "string") {
console.log(name)
} else {
var i;
for(i = 0;i
联合类型数组
var arr:number[]|string[];
var i:number;
arr = [1,2,4]
console.log("**数字数组**")
for(i = 0;i
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。
interface IPerson {
firstName:string,
lastName:string,
sayHi: ()=>string
}
var customer:IPerson = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"}
}
console.log("Customer 对象 ")
console.log(customer.firstName)
console.log(customer.lastName)
console.log(customer.sayHi())
var employee:IPerson = {
firstName:"Jim",
lastName:"Blakes",
sayHi: ():string =>{return "Hello!!!"}
}
console.log("Employee 对象 ")
console.log(employee.firstName)
console.log(employee.lastName)
编译以上代码,得到以下 JavaScript 代码:
var customer = {
firstName: "Tom",
lastName: "Hanks",
sayHi: function () { return "Hi there"; }
};
console.log("Customer 对象 ");
console.log(customer.firstName);
console.log(customer.lastName);
console.log(customer.sayHi());
var employee = {
firstName: "Jim",
lastName: "Blakes",
sayHi: function () { return "Hello!!!"; }
};
console.log("Employee 对象 ");
console.log(employee.firstName);
console.log(employee.lastName);
联合类型和接口
interface RunOptions {
program:string;
commandline:string[]|string|(()=>string);
}
// commandline 是字符串
var options:RunOptions = {program:"test1",commandline:"Hello"};
console.log(options.commandline)
// commandline 是字符串数组
options = {program:"test1",commandline:["Hello","World"]};
console.log(options.commandline[0]);
console.log(options.commandline[1]);
// commandline 是一个函数表达式
options = {program:"test1",commandline:()=>{return "**Hello World**";}};
var fn:any = options.commandline;
console.log(fn());
编译以上代码,得到以下 JavaScript 代码:
// commandline 是字符串
var options = { program: "test1", commandline: "Hello" };
console.log(options.commandline);
// commandline 是字符串数组
options = { program: "test1", commandline: ["Hello", "World"] };
console.log(options.commandline[0]);
console.log(options.commandline[1]);
// commandline 是一个函数表达式
options = { program: "test1", commandline: function () { return "**Hello World**"; } };
var fn = options.commandline;
console.log(fn());
接口和数组
interface namelist {
[index:number]:string
}
// 类型一致,正确
var list2:namelist = ["Google","Mobanw","Taobao"]
// 错误元素 1 不是 string 类型
// var list2:namelist = ["Mobanw",1,"Taobao"]
接口继承
单继承实例
interface Person {
age:number
}
interface Musician extends Person {
instrument:string
}
var drummer = {};
drummer.age = 27
drummer.instrument = "Drums"
console.log("年龄: "+drummer.age)
console.log("喜欢的乐器: "+drummer.instrument)
编译以上代码,得到以下 JavaScript 代码:
var drummer = {};
drummer.age = 27;
drummer.instrument = "Drums";
console.log("年龄: " + drummer.age);
console.log("喜欢的乐器: " + drummer.instrument);
多继承实例
interface IParent1 {
v1:number
}
interface IParent2 {
v2:number
}
interface Child extends IParent1, IParent2 { }
var Iobj:Child = { v1:12, v2:23}
console.log("value 1: "+Iobj.v1+" value 2: "+Iobj.v2)
定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):
字段 − 字段是类里面声明的变量。字段表示对象的有关数据。
构造函数 − 类实例化时调用,可以为类的对象分配内存。
方法 − 方法为对象要执行的操作。
创建类的数据成员
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log("发动机为 : "+this.engine)
}
}
编译以上代码,得到以下 JavaScript 代码:
var Car = /** @class */ (function () {
// 构造函数
function Car(engine) {
this.engine = engine;
}
// 方法
Car.prototype.disp = function () {
console.log("发动机为 : " + this.engine);
};
return Car;
}());
实例化对象
// 创建一个对象
var obj = new Car("XXSY1")
// 访问字段
console.log("读取发动机型号 : "+obj.engine)
// 访问方法
obj.disp()
类的继承
class Shape {
Area:number
constructor(a:number) {
this.Area = a
}
}
class Circle extends Shape {
disp():void {
console.log("圆的面积: "+this.Area)
}
}
var obj = new Circle(223);
obj.disp()
编译以上代码,得到以下 JavaScript 代码:
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 Shape = /** @class */ (function () {
function Shape(a) {
this.Area = a;
}
return Shape;
}());
var Circle = /** @class */ (function (_super) {
__extends(Circle, _super);
function Circle() {
return _super !== null && _super.apply(this, arguments) || this;
}
Circle.prototype.disp = function () {
console.log("圆的面积: " + this.Area);
};
return Circle;
}(Shape));
var obj = new Circle(223);
obj.disp();
需要注意的是子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承,如下实例:
class Root {
str:string;
}
class Child extends Root {}
class Leaf extends Child {} // 多重继承,继承了 Child 和 Root 类
var obj = new Leaf();
obj.str ="hello"
console.log(obj.str)
编译以上代码,得到以下 JavaScript 代码:
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 Root = /** @class */ (function () {
function Root() {
}
return Root;
}());
var Child = /** @class */ (function (_super) {
__extends(Child, _super);
function Child() {
return _super !== null && _super.apply(this, arguments) || this;
}
return Child;
}(Root));
var Leaf = /** @class */ (function (_super) {
__extends(Leaf, _super);
function Leaf() {
return _super !== null && _super.apply(this, arguments) || this;
}
return Leaf;
}(Child)); // 多重继承,继承了 Child 和 Root 类
var obj = new Leaf();
obj.str = "hello";
console.log(obj.str);
继承类的方法重写
类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。
其中 super 关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。
class PrinterClass {
doPrint():void {
console.log("父类的 doPrint() 方法。")
}
}
class StringPrinter extends PrinterClass {
doPrint():void {
super.doPrint() // 调用父类的函数
console.log("子类的 doPrint()方法。")
}
}
static 关键字
static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。
class StaticMem {
static num:number;
static disp():void {
console.log("num 值为 "+ StaticMem.num)
}
}
StaticMem.num = 12 // 初始化静态变量
StaticMem.disp() // 调用静态方法
instanceof 运算符
instanceof 运算符用于判断对象是否是指定的类型,如果是返回 true,否则返回 false。
class Person{ }
var obj = new Person()
var isPerson = obj instanceof Person;
console.log("obj 对象是 Person 类实例化来的吗? " + isPerson);
访问控制修饰符
TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。
public(默认) : 公有,可以在任何地方被访问。
protected : 受保护,可以被其自身以及其子类访问。
private : 私有,只能被其定义所在的类访问。
class Encapsulate {
str1:string = "hello"
private str2:string = "world"
}
var obj = new Encapsulate()
console.log(obj.str1) // 可访问
console.log(obj.str2) // 编译错误, str2 是私有的
类和接口
interface ILoan {
interest:number
}
class AgriLoan implements ILoan {
interest:number
rebate:number
constructor(interest:number,rebate:number) {
this.interest = interest
this.rebate = rebate
}
}
var obj = new AgriLoan(10,1)
console.log("利润为 : "+obj.interest+",抽成为 : "+obj.rebate )
编译以上代码,得到以下 JavaScript 代码:
var AgriLoan = /** @class */ (function () {
function AgriLoan(interest, rebate) {
this.interest = interest;
this.rebate = rebate;
}
return AgriLoan;
}());
var obj = new AgriLoan(10, 1);
console.log("利润为 : " + obj.interest + ",抽成为 : " + obj.rebate);
对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象等,如下实例:
var object_name = {
key1: "value1", // 标量
key2: "value",
key3: function() {
// 函数
},
key4:["content1", "content2"] //集合
}
TypeScript 类型模板
var sites = {
site1: "Mobanw",
site2: "Google",
sayHello: function () { } // 类型模板
};
sites.sayHello = function () {
console.log("hello " + sites.site1);
};
sites.sayHello();
此外对象也可以作为一个参数传递给函数,如下实例:
var sites = {
site1:"Mobanw",
site2:"Google",
};
var invokesites = function(obj: { site1:string, site2 :string }) {
console.log("site1 :"+obj.site1)
console.log("site2 :"+obj.site2)
}
invokesites(sites)
鸭子类型(Duck Typing)
鸭子类型(英语:duck typing)是动态类型的一种风格,是多态(polymorphism)的一种形式。
在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
interface IPoint {
x:number
y:number
}
function addPoints(p1:IPoint,p2:IPoint):IPoint {
var x = p1.x + p2.x
var y = p1.y + p2.y
return {x:x,y:y}
}
// 正确
var newPoint = addPoints({x:3,y:4},{x:5,y:1})
// 错误
var newPoint2 = addPoints({x:1},{x:4,y:3})
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { }
export class SomeClassName { }
}
要在另外一个命名空间调用语法格式为:
SomeNameSpaceName.SomeClassName;
如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:
///
1
IShape.ts 文件代码:
namespace Drawing {
export interface IShape {
draw();
}
}
Circle.ts 文件代码:
///
namespace Drawing {
export class Circle implements IShape {
public draw() {
console.log("Circle is drawn");
}
}
}
Triangle.ts 文件代码:
///
namespace Drawing {
export class Triangle implements IShape {
public draw() {
console.log("Triangle is drawn");
}
}
}
TestShape.ts 文件代码:
///
///
///
function drawAllShapes(shape:Drawing.IShape) {
shape.draw();
}
drawAllShapes(new Drawing.Circle());
drawAllShapes(new Drawing.Triangle());
使用 tsc 命令编译以上代码:
tsc --out app.js TestShape.ts
使用 node 命令查看输出结果为:
$ node app.js
Circle is drawn
Triangle is drawn
嵌套命名空间
namespace namespace_name1 {
export namespace namespace_name2 {
export class class_name { }
}
}
成员的访问使用点号 . 来实现,如下实例:
Invoice.ts 文件代码:
namespace Mobanw {
export namespace invoiceApp {
export class Invoice {
public calculateDiscount(price: number) {
return price * .40;
}
}
}
}
InvoiceTest.ts 文件代码:
///
var invoice = new Mobanw.invoiceApp.Invoice();
console.log(invoice.calculateDiscount(500));
使用 tsc 命令编译以上代码:
tsc --out app.js InvoiceTest.ts
使用 node 命令查看输出结果为:
$ node app.js
200
模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类地,我们必须通过 import 导入其他模块导出的变量、函数、类等。
两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。
模块导出使用关键字 export 关键字:
// 文件名 : SomeInterface.ts
export interface SomeInterface {
// 代码部分
}
要在另外一个文件使用该模块就需要使用 import 关键字来导入:
import someInterfaceRef = require("./SomeInterface");
IShape.ts 文件代码:
///
export interface IShape {
draw();
}
Circle.ts 文件代码:
import shape = require("./IShape");
export class Circle implements shape.IShape {
public draw() {
console.log("Cirlce is drawn (external module)");
}
}
Triangle.ts 文件代码:
import shape = require("./IShape");
export class Triangle implements shape.IShape {
public draw() {
console.log("Triangle is drawn (external module)");
}
}
TestShape.ts 文件代码:
import shape = require("./IShape");
import circle = require("./Circle");
import triangle = require("./Triangle");
function drawAllShapes(shapeToDraw: shape.IShape) {
shapeToDraw.draw();
}
drawAllShapes(new circle.Circle());
drawAllShapes(new triangle.Triangle());
使用 tsc 命令编译以上代码(AMD/commonjs):
tsc --module amd TestShape.ts
tsc --module commonjs TestShape.ts
输出结果为:
Cirlce is drawn (external module)
Triangle is drawn (external module)
在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。
假如我们想使用第三方库,比如 jQuery,但是在 TypeScript 中,我们并不知道 $ 或 jQuery 是什么东西,这时,我们需要使用 declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对:
declare var jQuery: (selector: string) => any;
jQuery('#foo');
declare 定义的类型只会用于编译时的检查,编译结果中会被删除。
声明文件
声明文件以 .d.ts 为后缀,例如:
Mobanw.d.ts
声明文件或模块的语法格式如下:
declare module Module_Name {
}
TypeScript 引入声明文件语法格式:
///
当然,很多流行的第三方库的声明文件不需要我们定义了,比如 jQuery 已经有人帮我们定义好了:jQuery in DefinitelyTyped。
以下定义一个第三方库来演示:
CalcThirdPartyJsLib.js 文件代码:
var Mobanw;
(function(Mobanw) {
var Calc = (function () {
function Calc() {
}
})
Calc.prototype.doSum = function (limit) {
var sum = 0;
for (var i = 0; i <= limit; i++) {
sum = sum + i;
}
return sum;
}
Mobanw.Calc = Calc;
return Calc;
})(Mobanw || (Mobanw = {}));
var test = new Mobanw.Calc();
如果我们想在 TypeScript 中引用上面的代码,则需要设置声明文件 Calc.d.ts,代码如下:
Calc.d.ts 文件代码:
declare module Mobanw {
export class Calc {
doSum(limit:number) : number;
}
}
声明文件不包含实现,它只是类型声明,把声明文件加入到 TypeScript 中:
CalcTest.ts 文件代码:
///
var obj = new Mobanw.Calc();
// obj.doSum("Hello"); // 编译错误
console.log(obj.doSum(10));
下面这行导致编译错误,因为我们需要传入数字参数:
obj.doSum("Hello");
使用 tsc 命令来编译以上代码文件:
tsc CalcTest.ts