TypeScript 是一种基于 JavaScript 的强类型编程语言。——来自官网描述。
1.是什么 & 为什么 **TypeScript 是什么:**微软在 JavaScript 的基础上,添加了一些类型的定义,推出了 TypeScript。
为什么要使用 TypeScript,而不使用 JavaScript:
JavaScript 的缺点JavaScript 1995 年被开发,至今版本很多(ES5、ES6)。 JavaScript 是弱类型语言。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 a = { name : 'js' , } a.number = 2 console .log (a) console .log (2 == '2' ) console .log (10 + 20 ) console .log (10 + '20' ) console .log ([1 ,2 ,3 ] + 4 )
TypeScript 的优点有类型定义。 兼容 JavaScript,是 JavaScript 的超集。 兼容的方式:将 TypeScript 编译成 JavaScript 运行。 补充:静态语言、动态语言、强类型语言、弱类型语言
静态语言与动态语言区别在于:何时得到数据的类型。(静态绑定:编译时绑定;动态绑定:运行时绑定)
静态语言:编译时检查类型。定义是需指明类型。 动态语言:运行时检查类型。定义时不需要指明类型。 强弱类型区别在于:运算过程中,当值的类型不符合运算规则时,是否能进行隐式转换。(隐式转换就是系统自动转换。)
2.TypeScript 的基础语法 大部分与 JavaScript 类似。
2.1 代码规范 整个项目规范要统一。
行末分号:加不加分号均可。
字符串的引号:双引号、单引号均可。
1 2 3 4 5 let name = 'Tom' let name = "Tom" console .log (name)console .log (name);
2.2 基础数据类型 (1)变量定义
只使用 let、const,不要使用 var。
1 2 let anExampleVariable = "abc" const anExampleNum = 123
(3)声明类型
变量名后面接类型。但是最好不要写,影响代码简洁,让编译器来推断。
1 2 3 let anExampleVariable : string = "abc" let anExampleNum : number = 123 let anExampleBool : boolean = true
(2)数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 let httpStatus : 200 | 404 | 500 | '200' | '404' | '500' = '200' function f (answer : 'yes' | 'no' | 'maybe' ) { console .log (answer) }let s1 = httpStatus let s2 : string = httpStatus httpStatus = s1 httStatus = s2
union of types 可能是多种类型。例如:status 可能是 string,也可能是 number。 1 2 3 4 function f (httpStatus : 200 | 404 | 500 | '200' | '404' | '500' ) { let status : string | number = httpStatus }
any 动态类型,意味着放弃 TypeScript 的所有类型检查,和 JavaScript 一样。 放弃类型检查,编写时不报错,但是运行时会报错。 1 2 3 4 5 let a : any = 'abc' a = 123 a.name = '123' console .log (a)
undefined undefined 类型变量不能被赋值为任何类型。可以与 literal type 结合使用,在对象类型、函数、接口中都会用到。 1 2 3 4 5 6 7 8 let s : undefined = undefined s = "111" console .log (s) function f (answer : 'yes' | 'no' | 'maybe' | undefined ) { console .log (answer) }
2.3 逻辑控制 (1)if
一律使用 ===
或 !==
。因为 ==
不同类型的变量也可以比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function processHttpStatus (s : '200' | '404' | '500' ) { if (s === '200' ) { console .log ('ok' ) } else if (s === '404' ) { console .log ('not found' ) } else if (s === '500' ) { console .log ('internal server error' ) } }processHttpStatus ('200' )processHttpStatus ('201' )
例:如果需要将传入的 number,全部转化为 string。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function processHttpStatus (s : '200' | '404' | '500' | 200 | 404 | 500 ) { let statusStr = '' if (typeof s === 'number' ) { statusStr = s.toString () } else { statusStr = s } if (statusStr === '200' ) { console .log ('ok' ) } else if (statusStr === '404' ) { console .log ('not found' ) } else if (statusStr === '500' ) { console .log ('internal server error' ) } }processHttpStatus ('200' )processHttpStatus (200 )
其中,转换为 strng 的代码也可以写成三元表达式:
1 2 const statusStr = typeof s === 'string' ? s.toString () : s
(2)switch
case 动作后需要加 break。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function processHttpStatus (s : '200' | '404' | '500' | 200 | 404 | 500 ) { let statusStr = '' if (typeof s === 'number' ) { statusStr = s.toString () } else { statusStr = s } switch (statusStr) { case '200' : console .log ('ok' ) break case '404' : console .log ('not found' ) break case '500' : console .log ('internal server error' ) break default : console .log ('unknown error' ) break } }processHttpStatus ('200' )processHttpStatus (200 )
(3)for
1 2 3 4 5 6 let sum = 0 for (let i = 0 ; i < 100 ; i++) { sum += i }console .log (sum)
(4)while
1 2 3 4 5 6 7 8 let sum = 0 let i = 0 while (i < 100 ) { sum += i i++ }console .log (sum)
(5)try/catch
例:如果 i 是 17 的倍数,就抛出错误。使用 try/catch 就能保证,即使出错,程序也不会立即退出。
1 2 3 4 5 6 7 8 9 10 11 12 13 let sum = 0 for (let i = 0 ; i < 100 ; i++) { try { sum += i if (i % 17 === 0 ) { throw `bad number ${i} ` } } catch (err) { console .error (err) } }console .log (sum)
2.4 枚举 枚举类型是 typesript 特有的数据类型,javascript 只能通过类来模拟枚举类型。
实际使用中,可以使用 literal type 或 enum。
枚举类型定义时,每个类型用 逗号 分隔。 不给每个类型设定值,默认是 0、1、2… 1 2 3 4 5 6 7 8 9 10 11 12 enum HTTPStatus { OK , NOT_FOUNT , INTERNAL_SERVER_ERROR , }function processHTTPStatus (s : HTTPStatus ) { console .log (s) console .log (HTTPStatus [s]) }processHTTPStatus (HTTPStatus .OK )
可以给每个类型设定值。 值既可以是数字,也可以是字符串。但是字符串的时候,无法使用 HTTPStatus[s],因为字符串不能作为索引。 1 2 3 4 5 6 7 8 9 10 11 12 enum HTTPStatus { OK = 200 , NOT_FOUNT = 404 , INTERNAL_SERVER_ERROR = 500 , }function processHTTPStatus (s : HTTPStatus ) { console .log (s) console .log (HTTPStatus [s]) }processHTTPStatus (HTTPStatus .OK )
2.5 数组 (1)定义
1 2 3 4 let arr = [1 , 2 , 3 ]console .log (arr)
(2)类型限定
1 2 3 4 5 6 let arr : number [] = [1 , 2 , 3 ]let arr : any [] = [1 , 'a' , true ] let arr : Array <number > = [1 , 2 , 3 ]let arr : (number | string )[] = [1 , ,2 , 3 , 'a' ]
(3)数组长度
1 2 let arr = [1 , 2 , 3 ]console .log (arr.length )
(4)取值
注:数组下标越界,不会报错。
1 2 3 4 let arr = [1 , 2 , 3 ]console .log (arr[0 ], a[1 ]) console .log (arr[4 ])
(5)空数组
通过长度判断是否为空数组:
1 2 3 4 5 6 7 let arr :number [] = []if (arr.length !== 0 ) { console .log ('arr is not empty' ) } else { console .log ('arr is empty' ) }
(6)尾部插入 push
1 2 3 4 let arr :number [] = [1 , 2 , 3 ] arr.push (4 )console .log (arr)
(7)尾部删除 pop
1 2 3 4 let arr :number [] = [1 , 2 , 3 ] arr.pop ()console .log (arr)
(8)首部插入 unshift
1 2 3 4 let arr :number [] = [1 , 2 , 3 ] arr.unshift (4 )console .log (arr)
(9)首部删除 shift
1 2 3 4 let arr :number [] = [1 , 2 , 3 ] arr.shift ()console .log (arr)
(10)数组的 const
1 2 3 4 5 6 const arr :number [] = [1 , 2 , 3 ] arr[2 ] = 0 arr.push (4 ) arr = [1 , 2 ]
(11)截取
slice 左闭右开,返回截取出来的数组,不会修改原数组。
1 2 3 4 5 6 7 8 9 const arr :number [] = [0 , 1 , 2 , 3 , 4 , 5 , 6 ]console .log (arr.slice (2 , 5 )) console .log (arr.slice (2 )) console .log (arr.slice (2 , 100 )) console .log (arr)
(12)更改部分元素
splice 删除部分元素,并返回被删除的元素。
1 2 3 4 5 6 const arr :number [] = [0 , 1 , 2 , 3 , 4 , 5 , 6 ]let deleted = arr.splice (3 , 2 ) console .log (deleted) console .log (arr)
1 2 3 4 5 6 const arr :number [] = [0 , 1 , 2 , 3 , 4 , 5 , 6 ]let deleted = arr.splice (3 , 2 , 0 , 0 , 0 ) console .log (deleted) console .log (arr)
(13)查找元素
1 2 3 4 5 6 7 8 9 10 const arr :number [] = [8 , 2 , 4 , 9 , 0 , 1 , 4 ]console .log (arr.indexOf (4 )) console .log (arr.indexOf (4 , 3 )) console .log (arr.lastIndexOf (4 )) console .log (arr.lastIndexOf (4 , 5 )) console .log (arr.indexOf (3 )) console .log (arr.lastIndexOf (3 ))
(14)排序
直接调用 sort 是按照字典序排序,主要是用来排字符串的。 1 2 3 4 const arr :number [] = [8 , 2 , 14 , 1 ] arr.sort ()console .log (arr)
1 2 3 4 5 6 7 8 9 function compareNumber (a :number , b :number ) { return a - b }const a = [2 ,13 ,21 ,4 ,5 ,1 ,42 ,3 ,7 ,9 ] a.sort (compareNumber)console .log (a)
(15)元组
1 2 3 4 const arr = [1 , 2 , 3 ]const [a1, a2, a3] = arrconsole .log (a1, a2, a3)
(16)分隔 split
1 2 3 4 5 let s = 'a,b,c,d,1,2,3,' let arr = s.split (',' )console .log (arr)
(17)连接 join
1 2 3 4 5 const arr = [1 , 2 , 3 ]console .log (arr.join ()) console .log (arr.join ('-' )) console .log (arr.join ('' ))
2.6 对象 不需要有类,可以直接手写对象 object。
(1)定义
对于没有初值的字段,可以赋值为 undefined;但该字段类型并不真的是 undefined,所以需要指明类型为 union of types。
1 2 3 4 5 6 7 8 const emp1 = { name : 'john' , gender : 'male' as ('male' | 'female' ), salary : 8000 , bonus : undefined as (undefined | number ) }console .log (emp1)
(2)嵌套
变量的值可以是 object、数组等各种类型。
1 2 3 4 5 6 7 8 9 const emp1 = { name : { first : 'san' , last : 'zhang' , }, gender : 'male' , }console .log (emp1)
(3)取值
可根据关系,直接 “点” 出来,或使用键值对的方式。
1 2 console .log (emp1.name .frist )console .log (emp1['name' ])
(4)JSON
JSON = JavaScript Object Notation。
在 JSON 中,键必须是字符串,由双引号包围。{ "name":"Bill Gates" }
在 JavaScript 中,键可以是字符串、数字或标识符名称。{ name:'Bill Gates' }
(5)JSON 与 string 转化
JSON.stringify(object)
和 JSON.parse(string)
。
注意: 下面的例子中,emp2 只能是 any 类型,因为编译器无法判断 JSON.parse(string)
会返回什么类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const emp1 = { name : { first : 'san' , last : 'zhang' , }, gender : 'male' , }console .log (emp1)const s :string = JSON .stringify (emp1)console .log (s)const emp2 = JSON .parse (s) console .log (emp2)
(6)对象的比较
不能直接比较,只能分别比较不同的字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const emp1 = { name : { first : 'san' , last : 'zhang' , }, gender : 'male' , }const emp2 = { name : { first : 'san' , last : 'zhang' , }, gender : 'male' , }console .log (emp1 === emp2)
2.7 函数 (1)函数定义
函数返回值可以声明,也可以不声明;但如果声明了返回值类型,不返回将报错。
1 2 3 4 5 6 7 8 9 function add (a :number , b :number ): number { return a + b }function add1 (a :number , b :number ) { return a + b }console .log (add (2 ,3 ))
(2)可选参数
可选参数后加 ?
,下面代码中,如果 c 未传入,类型就是 undefined,所以需要判断一下。
判断可选参数的简便写法:return c ? a + b + c : a + b
,return a + b + (c || 0)
。
1 2 3 4 5 6 7 8 9 10 function add (a :number , b :number , c ?: number ): number { if (c) { return a + b + c } else { return a + b } }console .log (add (2 , 3 ))console .log (add (2 , 3 , 4 ))
(3)默认参数
参数可以设置默认值。
1 2 3 4 5 6 7 8 9 10 function add (a :number , b :number , c ?: number , d : number =0 ): number { if (c) { return a + b + c + d } else { return a + b + d } }console .log (add (2 , 3 ))console .log (add (2 , 3 , 4 , 5 ))
(4)可变参数列表
1 2 3 4 5 6 7 8 9 10 function add (a :number , b :number , c ?: number , d : number =0 , ...e : number [] ): number { let sum = a + b + (c || 0 ) + d for (let i = 0 ; i < e.length ; i++) { sum += e[i] } return sum }console .log (add (2 , 3 ))console .log (add (2 , 3 , 4 , 5 , 6 , 7 , 8 ))
(5)数组参开当可选参数列表
1 2 3 4 5 6 7 8 9 10 function add (a :number , b :number , ...e :number [] ): number { let sum = a + b for (let i = 0 ; i < e.length ; i++) { sum += e[i] } return sum }const numberList = [5 , 6 , 7 , 8 ]console .log (add (1 , 2 , 3 , 4 , ...numberList))
(6)函数重载(不推荐使用)
推荐使用可变参数列表、默认参数、可选参数、union type。
typescript 的函数重载很:有多个声明,但只有一个函数实现,这个函数要兼容所有函数声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 function add (a : number , b :number ):number function add (a :number , b :number , ...e :number [] ): number function add (a :number , b :number , ...e :number [] ): number { let sum = a + b for (let i = 0 ; i < e.length ; i++) { sum += e[i] } return sum }const numberList = [5 , 6 , 7 , 8 ]console .log (add (1 , 2 , 3 , 4 , ...numberList))console .log (add (1 , 2 ))function add (x :string ,y :string ):number ;function add (x :number , y :number ):number ;function add (x :string |number , y : number |string ): number | string { if (typeof x === 'string' ) { return (+x) + (+y); }else { return x + (y as number ); } }console .log (add (1 , 2 ))console .log (add ('2' , '3' ))
(7)对象类型作为参数
不使用对象类型参数时,调用函数时,参数太多,写代码和看代码的人都不容易明确每个参数的含义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function sendRequest ( url : string , method : 'GET' | 'POST' | 'PUT' , header : object , data : string , requireAuth : boolean , retey : boolean , retryTimeout : number ) { console .log ("success" ) }sendRequest ('https://www.bing.com' , 'GET' , {contentType : 'application/json' ,}, '{"name":"john"}' , true , true , 300000 )
使用对象类型参数时,增加代码可读性。params:Parameters,参数。
TypeScript/JavaScript 创建对象很方便,所以要有使用对象类型的意识。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 function sendRequest (params : { // params url: string , method: 'GET' | 'POST' | 'PUT' , header: object , data: string , requireAuth: boolean , retey: boolean , retryTimeout: number } ) { console .log ("success" ) }sendRequest ({ url : 'https://www.bing.com' , method : 'GET' , header : { contentType : 'application/json' , }, data : '{"name":"john"}' , requireAuth : true , retey : true , retryTimeout : 300000 })
2.8 对象的方法 对象中可以定义方法,this 关键字指代当前大括号的这个对象。
注意:this 有坑,当嵌套的对象过多时,this 指代谁就不一定了。解决办法:函数式编程可以解决。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const emp1 = { name : 'john' , gender : 'male' as ('male' | 'female' ), salary : 8000 , bonus : undefined as (undefined | number ), performance : 3.5 , updateBonus ( ) { if (!this .bonus ) { this .bonus = this .salary * this .performance } } }console .log (emp1.bonus ) emp1.updateBonus ()console .log (emp1.bonus )
3.函数式编程 初学者很难理解函数式编程的优势,在学习过程中,可以先理解逻辑,在实际编码中了解其优势。
graph LR
A(函数式编程)--> B1(函数是一等公民)
B1 --> C1(变量类型可以是函数)
B1 --> C2(值可以是函数)
B1 --> C3(对象字段的值可以是函数)
B1 --> C4(函数参数可以是函数)
B1 --> C5(函数返回值可以是函数)
A --> B2(高阶函数)
A --> B3(闭包)
A --> B4(部分应用函数)
A --> B5(惰性计算)
A --> B6(引用透明性)
A --> B7(无副作用)
3.1 函数是一等公民 (1)变量可以是函数
定义变量时,变量类型为:let compareNumber: (a: number, b: number) => number
,第一出现时,编译器根据函数,确定了这个函数的参数和返回值类型。
再给 compareNumber 赋值的时候,只能赋值 (a: number, b: number) => number
类型函数。
1 2 3 4 5 6 7 8 9 10 11 12 let a = [2 ,13 ,21 ,4 ,5 ,1 ,42 ,3 ,7 ,9 ]let compareNumber = function (a :number , b :number ) { return a - b } a.sort (compareNumber) compareNumber = function (a :number , b :number ) { return b - a } a.sort (compareNumber)
(2)值(literal)可以是函数
如上面的代码,函数在等号右边,是作为值。
(3)对象的字段的值可以是函数
1 2 3 4 5 6 7 8 9 const emp1 = { name : 'john' , salary : 8000 , getBonus : function (performance : number ) { return this .salary * performance } }console .log (emp1.getBonus (1.1 ))
(4)函数参数可以是函数
1 2 3 4 5 6 7 function compareNumber (a :number , b :number ) { return a - b }let a = [2 ,13 ,21 ,4 ,5 ,1 ,42 ,3 ,7 ,9 ] a.sort (compareNumber)
(5)函数返回值可以是函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function compareNumber (params : {smallerFirst: boolean } ) { if (params.smallerFirst ) { return (a :number , b :number ) => { console .log (a, b) return a - b } } else { return (a :number , b :number ) => { console .log (a, b) return b - a } } }let a = [2 ,13 ,21 ,4 ,5 ,1 ,42 ,3 ,7 ,9 ] a.sort (compareNumber ({smallerFirst :true }))
3.2 补充:lambda expression expression:表达式
在 JS/TS 中,叫 Arrow Function(箭头函数)
1 2 3 4 let a = [2 ,13 ,21 ,4 ,5 ,1 ,42 ,3 ,7 ,9 ]let compareNumber = (a :number , b :number ) => a-b a.sort (compareNumber)
1 2 3 4 5 6 7 let a = [2 ,13 ,21 ,4 ,5 ,1 ,42 ,3 ,7 ,9 ]let compareNumber = (a :number , b :number ) => { console .log (a, b) return a-b } a.sort (compareNumber)
3.2 高阶函数 在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
在 3.1 函数是一等公民 中,可以看到,TS 有高阶函数的能力。