一、概述
1、什么是Typescript?
官方网站的定义是: TypeScript 是 JS 类型的超集,TypeScript 是一个js的外壳,需要编译成浏览器可识别的javascript才可以运行。
2、为什么使用Typescript?
- 弥补javascript缺少类型判断,缺少结构化机制(类、模块、接口等)的不足
- 程序更容易理解 (‘代码即注释’)
- 效率更高(编译期就会发现大部分错误)
- 非常好的包容性(完全兼容js、流行项目都支持Ts)
不足:增加了一些学习成本,短期内增加了一些成本,项目规模小,无必要使用
二、安装和初试
- 安装
npm install -g typescript
- 编译
tsc file.ts
- 简便方法,安装ts-node
每次都需要对ts文件编译产生js文件后再通过node 运行,比较麻烦
npm i ts-node -gts-node file.ts
三、数据类型
原始数据类型
Boolean
let isDone: boolean = false;
Null
let null = null
Undefined
let undefined = undefined
Symbol
String
let firstName:string = “jimmy”
Number
let age: number = 20 | 0b1111;
注意: undefined和null是其他类型的子集
Eg:
let num: number = undefined | null
- any类型,有明确类型避免使用
let notSure :any = 4 notSure = ‘1233’ notSure = true
- 联合类型(|)
let numberOrString : number | string = 23
- 数组类型
let arrOfNumbers:number[] = [1,2,3,4] arrOfNumbers.push(1) arrOfNumbers.push(‘1’) // error
- Tuple—特殊定义数组类型的方式
let user:[string,number] = [‘hello’, 99] user = [“world”,”haha”] // error
- interface
| 对对象的形状进行描述
| 对类进行抽象
| 鸭子类型 对象的推断,而不是对象本身
interface IPerson{readonly id:number;name:string;age?:number;}let tom: IPerson = {name : 'tom',id:1,age:19}// 注意: age后面的问号代表可选属性,代表该属性可以不存在,readonly代表只读属性,代表对象中的该属性只能读不能修改。注意接口命名首字母需要大写,I开头不强制, 每个属性定义后用";" 结尾
- 函数类型
// 对参数和返回值的约定const add = function(x:number,y:number,z?:number =10):number{if(typeof m === 'number'){return x + y + m}else{return x + y}}// let result = add(1,2)// let result = add(1,2,3)// z为可选类型可选类型放参数最后面// 类型推断,可以根据赋值推断变量类型const add2: string = add // errorconst add2:(x:number,y:number,z?:number =10)=>number = add // trueeg:let str = "hello"str = 123 // errorstr = "world" // true
- class类的支持
// 创建Animate类class Animate{public name:string; // 公有属性|默认属性readonly id:number; // 只读,不可修改赋值private size:number; // 私有方法,只有自己可以访问protected key:boolean;// 受保护的属性,自己和子类可以使用static categoies:string[] = ["mammal",brid]; // 静态属性static isAnimal(a){ // 静态方法return a instanceof Animate}constructor(name){this.name = name;}run(){return `${this.name} is running`}}// 继承父类class Cat extends Animate{constructor(name,key){super(name) // 继承父类的方法this.name = name;this.key = key;run(){ // 重写父类run方法return 'Meow, ' + super.run()}}}const cat = new Cat('miao',true)console.log(cat.run()) // 'Meow, miao is running'
- 类和接口的使用—-implements
// 提取公共的接口interface Radio{switchRadio(trriger:boolean) : void | number;}// Cellphone特有interface Battery{checkBattertStatus();}class Car implements Radio{switchRadio(){}}class Cellphone implements Radio,Battery{switchRadio(){}checkBattertStatus(){}}// 定义接口继承已有interface RadioWithBattery extends Radio{checkBattertStatus();}class Cellphone implements checkBattertStatus{switchRadio(){}checkBattertStatus(){}}
- 枚举Enums
一般声明常量中使用,并且有一定关系
数字枚举
enum Direction{Up,Down,Right,Left}console.log(Direction.Up) // 0console.log(Direction.Down) // 1console.log(Direction[0]) // Up可以给Up赋值,后面的会递增
字符串枚举
enum Direction{Up='UP',Down='DOWN',Right='RIGHT',Left='LEFT',}const value = 'UP'if(Direction['UP']===value){console.log('go up')}
常量枚举
只需要在枚举前面加const,会内联枚举,提高计算性能
const enum Direction{Up='UP',Down='DOWN',Right='RIGHT',Left='LEFT',}
- 泛型——generics
泛型出现的动机和要解决的问题:
在定义时没办法确定参数类型和返回类型的时候,在使用时才能确定
可以简单理解为占位符,动态指定类型
function echo(arg:number){return arg}const result = echo(123) // result is numberconst result = echo('123') // result is string change arg is string...
result无法随意匹配any类型
改造后:
function echo<T>(arg:T):T{ // 使用T作为参数占位return arg}const result:number = echo(123)const result:string = echo('123')const result:boolean = echo(true)
参数是一个数组的时候,加泛型
function swap<T,U>(tuple:[T,U]):[U,T]{return [tuple[1],tuple[0]]}const result2 = swap(['string',123])result2[1] // numberresult2[0] // string
对函数使用泛型加约束
Eg:
function echoWithArr<T>(arg:T):T{console.log(arg.length)return arg}// 会报错,因为T可能没有length,如果给T加约束function echoWithArr<T>(arg:T[]):T[]{console.log(arg.length)return arg}// 改造成了传T类型的数组,错误取消,但是如果想判断字符串的length呢,如果是对象中含有length呢,上面的改造就不能实现了,继续改造interface IWithLength{length:number;}function echoWithLength<T extends IWithLength>(arg:T):T{console.log(arg.length)return arg}const str = echoWithLength('str')const obj = echoWithLength({length:12,width:'12'})const arr = echoWithLength([1,2,3])// 以上都可以满足,问题解决
对类使用泛型约束
class Queue<T>{private data = [];push(item:T){return this.data.push(item)}pop():T{return this.data.shift()}}const queue = new Queue<number>();queue.push(1)const queue2 = new Queue<string>();queue.push('1')
对接口加泛型
interface KeyPair<T,U>{key:T;value:U;}let kp1:KeyPair<number,string> = {key:123,value="str"}let kp2:KeyPair<string,number> = {key:"str",value="123"}
对数组加泛型
let arr:number[] = [1,2,3]let arr2:Array<number> = [1,2,3,4]
interface IPlus<T> { // 描述了一个函数的类型{a:T,b:T}: T}function plus(a:number,b:number){return a+b;}function connect(a:string,b:string){return a+b;}const a:IPus<number> = plus;const b:IPus<string> = plus;
- 类型别名和断言as
// 别名 type aliasesfunction sum(x;number,y:number):number {return x+y}const sum2:(x;number,y:number)=>number = sum// sum2 太长,用类型别名type PlusType = (x;number,y:number)=>numberconst sum2:PlusType = sum
// 断言 as 分别判断不同类型的不同处理方式function sum(input:string | number) :number {const str = input as String;if(str.length){return str.length}else{const number = input as Number;return number.toString().length}}=>function sum(input:string | number) :number {if((<string>input).length){return (<string>input).length}else{return input.toString().length}}
- 声明文件
jQuery('#f00');
使用一
declare var jQuery:(selector:string)=>any
一般单独放在一个文件jQuery.t.ts 中声明,以.d.ts结尾
tsconfig.json
{"include":["**/ *]}
使用二
第三方库
npm install —save @types/jquery
四、Ts高级类型
1、交叉类型 &
使用 & 符号构造交叉类型
type LeftType = {id: numberleft: string}type RightType = {id: numberright: string}type IntersectionType = LeftType & RightTypefunction showType(args: IntersectionType) {console.log(args)}showType({id: 1, left: "test", right: "test"})
2、联合类型 |
使用 | 符号构造交叉类型
type UnionType = string | numberfunction showType(arg: UnionType) {console.log(arg)}showType("test")// Output: testshowType(7)// Output: 7
3、泛型
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
interface GenericType<T, U> {id: Tname: U}function showType(args: GenericType<number, string>) {console.log(args)}showType({ id: 1, name: "test" })// Output: {id: 1, name: "test"}function showTypeTwo(args: GenericType<string, string[]>) {console.log(args)}showTypeTwo({ id: "001", name: ["This", "is", "a", "Test"] })// Output: {id: "001", name: Array["This", "is", "a", "Test"]}
4、内置类型
Partial 类型 (将T类型的所有必选属性设为可选属性)
interface PartialType{id:number,name:string}function showType(args:Partial<PartialType>){console.log(args)}showType({1})
Required 类型 (将T类型的所有可选属性设为必选属性)
interface PartialType{id:number,name?:string}function showType(args:Required<PartialType>){console.log(args)}showType({1,'xiaohua'})
Readonly 类型 (将T类型的所有属性设置为只读,如果赋值保错)
interface ReadonlyType{id:number,name:string}function showType(args:Readonly<ReadonlyType>){args.id = 5 // Error: Cannot assign to 'id' because it is a read-only property.}showType({1,'xiaohua'})
Pick类型 从T中取出K中选择出指定的属性
interface PickType{id:number,name:string,firstName:string}function showType(args:Pick<PickType,"name"|"firstName">){console.log(args)}showType({ name: "John", firstName: "Doe" }) //=> JohnshowType({ id: 3 }) //=> Error: Object literal may only specify known properties...
Omit类型 与Pick相反, 从T中选取K属性进行删除 ```javascript interface PickType { id: number firstName: string lastName: string }
function showType(args: Omit
showType({ id: 7 }) // Output: {id: 7}
showType({ firstName: “John” }) // Error: Object literal may only specify known properties,
<a name="Hae1O"></a>#### 5、Extract- `Extract`<br />`Extract` 从 `T` 中提取所有可分配给 `U` 的类型。 有多个共同字段,`Extract` 将提取所有共同的属性```jsoninterface FirstType {id: numberfirstName: stringlastName: string}interface SecondType {id: numberaddress: stringcity: string}type ExtractType = Extract<keyof FirstType, keyof SecondType>// Output: "id"
- Exclude 从T中排除分配给U的类型 ```json interface FirstType { id: number firstName: string lastName: string }
interface SecondType { id: number address: string city: string }
type ExcludeType = Exclude
// Output; “firstName” | “lastName” ```
