TypeScript基础教程

ts与js区别

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才能被浏览器执行。

TypeScript基础教程_第1张图片

一、TypeScript基础类型:

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) {}
}

二、TypeScript 变量声明

变量的命名规则:_、$, 不能以数字开头
包含字母、数字、
声名变量及初始值:

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)

三、TypeScript 运算符

  1. 算术运算符

+、 -、 *、 /、 %、 ++、 –

  1. 逻辑运算符

&&、 ||、 !

  1. 关系运算符

==、 !=、 >、 <、 >=、 <=

  1. 按位运算符
    |运算符|描述|例子|类似于|结果|十进制|
    |–|–|–|–|–|–|
    |&|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|

  2. 赋值运算符

=、 +=、 -=、 *=、 /=、

  1. 三元/
var num:number = -2 
var result = num > 0 ? "大于 0" : "小于 0,或等于 0" 
console.log(result)
  1. 字符串运算符
var msg:string = "Mobanw"+".COM" 
console.log(msg)
  1. 类型运算符
var num = 12 
console.log(typeof num);   //输出结果: number

四、TypeScript 条件语句(和js相同)

if、 if…else、 if…else if…else、 switch

五、TypeScript 循环

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
});

六、TypeScript 函数

// 函数定义
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");

七、TypeScript Number

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

八、TypeScript String(字符串)

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() 返回指定字符串对象的原始值

九、TypeScript Array(数组)

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

十、TypeScript Map 对象

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

十一、TypeScript 元组

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 )

十二、TypeScript 联合类型

联合类型(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

十三、TypeScript 接口

接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。

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)

十四、TypeScript 类

定义类的关键字为 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);

十五、TypeScript 对象

对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象等,如下实例:

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})

十六、TypeScript 命名空间

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

十七、TypeScript 模块

模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面变量、函数和类等在模块外部是不可见的,除非明确地使用 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)

十八、TypeScript 声明文件

在开发过程中不可避免要引用其他第三方的 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

你可能感兴趣的:(前端,typescript,ubuntu,javascript)