简介:
它是 JavaScript 的一个超集,支持 ECMAScript 6 标准,由微软公司开发的自由、开源的编程语言,扩展了javaScript 得语法,它的设计目标是开发大型应用,全部浏览器兼容。
它有更多的规则和类型限制:代码具有更高的预测性、可控性,易于维护和调试;对模块、命名空间和面向对象的支持,更容易组织代码开发大型复杂程序。
它是一个超集:是一个编译到纯 JS 的有类型定义的 JS 超集,遵循当前以及未来的 ECMAScript规范。不仅能兼容现有的 JS 代码,它也拥有兼容未来版本的
超强代码能力:大多数 TS 的新增特性都是基于未来的 JS 提案。许多 TS 代码在将来很有可能会变成 ECMA 的标准。
面向对象增强:TS是对面向对象思想进行了增强,使前端变成了强语言类型
JavaScript 发展迅速:TypeScript 可以降低 JavaScript 弱语言的脆弱性,减少由于不正确类型导致错误产生的风险
需要强类型的 JavaScript:TypeScript 把高级语言的强类型引入 JavaScript ,解决了防止在编写 JavaScript 代码时因为数据类型的转换造成的错误。
主流框架及最新特性的支持:Angular 2.0 版本就开始集成 TypeScript,React 、Vue也要加入 TypeScript 的阵营,能用最新的语言特性,编写质量更高的 JavaScript。
安装
npm install -g typescript/ cnpm install -g typescript 安装
tsc -v 查看版本
运行ts
新建ts 文件index.ts.
ts 语法无法直接在浏览器运行,需要编译成js 语法,使用如下命令 tsc index.ts (缺点:每次更新,都需要重新编译)
tsc --init 初始化文件夹和自动监测
tsc -w 自动监测同步 JS 文件
ts的数据类型
boolean类型:let a:boolean= false
number类型:它不仅支持二进制、八进制和十进制及十六进制的格式
string 类型:let str:string = "过年好";
undefined /null:let n:null = null;
void 类型
function warnUser(): void { console.log("This is my warning message"); }
any 类型:let a1: any = {}在不清楚明确类型时
unknown类型:let u1: unknown = 100,它是 3.0 时引入类型,是 any 类型对应的安全类型,定义时比 any 类型更加严格,执行操作之前,必须进行某种形式的检查
never类型:它是其它类型的子类型,代表从不会出现的值,never 变量只能被 never 类型所赋值,函数中它表现为抛出异常或无法执行到终止点
function loop(): never { while (true) { } } function error(m: string): never { throw new Error(m) }
数组类型:let arr2: Array<any> = [1, 3, 5, 6, 100, '100', [10, 20]];
元组类型:数组中每一个值都有具体类型,在赋值时必须遵循定义的顺序和类型,它是一种严格的数组,let arr3: [string, number, boolean] = ['', 1, false]
object类型:表示非原始类型,也就是除number,string,boolean,symbol,null 或 undefined 之外的类型,let obj: object = { name: "李焕英", age: 20 }
枚举类型:enum sex { male, female, unknown }
多个类型:let a:number|string|undefined = 100
枚举类型:它是对 JavaScript 标准数据类型的补充,声明一组带名字的常量,当一个变量有多个取值的可能时,就可以定义为枚举型
enum xxx{ 枚举名称 }
1.数字型枚举
当定义的枚举型成员是数字时,那么,该枚举就是数字型枚举,成员的数字既可以是指定的数字值,也可以是索引号,默认值从 0 开始,依次类推
enum direction { up = 10, dowm = 88, left = 10, right = 99 }
2.字符型枚举
在定义的枚举类型中,每个成员都是字符型字面量,它无法进行累加也不能初始化索引号,仅是给每个成员取了一个可读的名字, 反向映射。
enum direction { up = 'up', dowm = 'down', left = 'left', right = 'right' }
3.异构型枚举
当一个定义好的枚举成员中,由数字和字符型联合构成,这种类型称之为异构型,即不同的类型构建在一起的枚举,(此类型很少使用)
enum status1{ success="ok", code=500 }
4.常量型枚举
它是在普通枚举的基础上,使用 const 修饰符来定义,一旦定义成常量型的枚举,它的成员值只能使用常量,并删掉整个枚举定义内容
let d = 199 const enum direction{ up=10, dowm, left=10, right = d 报错 }
2、反向映射
枚举类型中,通过成员名,可以很方便地访问到成员值,同时,通过成员值,也可以返回成员名称,这种方式称之为反向映射
enum direction { up = 'up1', dowm = 'down1', left = 'left1', right = 'right1' } direction['dowm'] = 'down1' 反过来 direction['down1'] = 'down'
3、枚举合并
多个枚举类型可以分开定义,并不会冲突,分开后,在编译时会自动合并,不影响成员中值的访问,具体代码如下:
enum direction { up = 10, dowm = 88, left = 10, right = 99 } enum direction { forward = 1000, backward = 2000 } console.log(direction) 合并到一块了
五、ts 中的函数
ts 中的函数需要指明参数类型和返回的数据类型
let fn = function (m:string,number):void{ } let fn1 = (m:string,number):string=>{ return `` }
1、可选参数和默认参数和剩余参数
可选参数? 可以不用传,注意:如果还有其他参数,可选参数不能作为第一个参数
可选参数在参数后+? function add(x:number,y?:number):number{ console.log(y) return y?x+y:x } 默认参数就是给参数赋值默认值 function fn1(name:string,sex:string ='男',age?:number):string{ return `${name}---${age}---${sex}` } 剩余参数 ...arr function fn2(name:string="老杨",age?:number,...arr:any[]):string{ console.log(name,age,arr) return `` } fn2(undefined,32,'男','北京','已婚')
2、函数得重载
定义在javasctipt 中,如果同一个函数参数不同,返回得类型也不同,这样需要我们定义2个或2个以上得该同名函数,这样就会出现函数重载得情况
function getUser(name: string): string function getUser(age: number): number function getUser(upanddowm: boolean): string 执行函数 function getUser(str: any): string | number | void { if (typeof str == 'string') { return `我叫${str}` } else if (typeof str == 'number') { return str } return str ? `你升班了` : `你末班了` } console.log(getUser('曹哲')) console.log(getUser(25)) console.log(getUser(false)) 报错 重载列表中没有于此匹配的项
六、深入理解接口和类
接口的定义: 指定结构的类型,并执行类型的检测,起到限制和规范的作用,说白了接口得作用主要是用来声明一种数据类型。而该数据类型必须是符合接口定义的规范。(通俗的讲,要想和接口对接,需要满足接口的合适插头)
接口的语法:使用 interface 关键字,后面添加接口的名称,并使用大括号描述接口中各结构属性的类型,完成定义后,可以像普通的类型一样使用它
interface Person{ name:string, age:number, } let p:Person = { name:"沈腾", age:40 }
1、接口属性
接口属性有 普通属性, 可选属性(?),只读属性(readonly)
普通属性:就是正常的属性
可选属性: 在使用该接口时,可选属性可传可不传。
只读属性:只读属性使用后,不能再次修改。
interface Person{ name?:string, readonly age:number, } let p:Person = { name:"沈腾", 可选属性 可传可不传 age:40 只读属性不能修改 }
2、接口定义函数
fn 表示一种函数数据类型 interface fn{ (m:string):void } let f1:fn = function(m:string){ console.log(m) } f1('郑爽')
3、接口中使用函数
如果在接口中有函数,可以在接口中直接定义
interface Men{ name?:string, readonly age:number, say:(m:string,n:number)=>string 第一种写法 say(m:string,n:number):string 第二种写法 }
也可以使用接口定义,再引入到接口中,这两种方式都可以实现
interface Say{ (m:string,n:number):string } interface Men{ name?:string, readonly age:number, say:Say } let bichen:Men = { name:"张碧晨", age:30, say:function(m:string,n:number):string{ return `${this.name}不结婚也要${m}` } }
3、可索引接口
定义:主要是来用定义数组或对象数据类型的。
1. 定义一个数组数据类型 interface arr{ [name:number]:any } let arr1:arr=['刘','关','张',100,{}]; 2. 定义一个对象数据类型 interface obj{ [name:string]:any } let obj1:obj={ "sex":"男", age:20 }
使用案例:
interface child{ name:string, age:number, say:()=>string, like:obj } let liuyan:child={ name:"刘衍", age:20, say:():string=>{ return `` }, like:{ "movie":"电影", "play":"lol" } } console.log(liuyan)
4、接口的继承
一个接口除被作为类型使用外,还可以被其他的接口继承,继承一个为单继承,二个以上为多接口继承,代码如下:
定义 women接口 interface women{ name:string, age:number, cook:(m:string)=>string } 定义 father接口 interface father{ work:()=>string } 定义 son接口继承women,father接口 interface son extends women,father{ play:string, study:()=>string } let zhanhzhenda:son={ name:"张郑达", age:20, cook:(m:string):string=>{ return `我喜欢做${m}` }, play:"lol", study:():string=>{ return`我要毕业上班` }, work:():string=>{ return `我要敲代码` } }
七、类的概念
在es5中使用函数创建类
function Girl(name,age){ this.name = name this.age = age this.say=function(){ } } let fanbingbing = new Girl('范冰冰',40) let liuyifei = new Girl('刘亦菲',32) console.log(fanbingbing) console.log(liuyifei)
在es6中使用class 创建类
注意:类的构造函数:constructor(){} ,一般在实例化类的时候,传参需要用constructor 构造函数接收参数的情形。所以这种情况下,才需要在类里写构造函数。否则不写。
指在构造(实例化)一个类时,执行的函数,故称为构造函数,它也是一个普通的函数,也能定义形参,在构造时传递实参, 该构造函数在实例化类的时候执行。如下:即在 new C('张三')的执行。
class Girl{ name:string; age:number; say():string{ return `大家好,我是${this.name}` } constructor(m:string,n:number){ 构造函数 this.name = m this.age = n } } let guanzhilin = new Girl('关之琳',40)
1、类的继承
-
在es6中,使用关键字 extends, super 实现类的继承。
-
允许使用继承来扩展现有的类,可通过 extends 关键字来完成,派生类通常被称作子类,基类通常被称作超类
-
super() 表示调用父类的constructor(){} 方法
-
如果父类和子类的有相同的方法名,调用子类的方法时,则会执行子类的方法。(也就是就近原则)
// 定义 Girl类 class Girl{ name:string; age:number; say():string{ return `大家好,我是${this.name}` } constructor(m:string,n:number){ 构造函数 this.name = m this.age = n } } // 定义学生类 继承 Girl类 class Student extends Girl{ grade:string; study():string{ return `我要学习web 前端` } say():string{ return `子类中方法,我是${this.name}` } constructor(m:string,n:number,g:string){ super(m,n) this.grade = g } }
2、类的修饰符
public 公有属性: public 是默认的,没有加修饰符的属性和方法都有公有属性和方法,即属性和方法都是公共的。特点在类里面,继承的子类中,实例化后都可以访问
protected 受保护属性 :protected是受保护的属性,在类里面,继承的子类中可以访问,在实例化后访问不了
private 私有属性 :private是私有属性,在类里面可以访问,继承的子类中无法访问,实例化后也无法访问
3、静态属性
存在于类本身上面而不是类的实例上,即无须实例化就可以访问的属性,称之为静态属性
1、先看es5中类的静态属性表示如下:
2、es6中类的静态属性
class Boy { static name1: string = '周杰伦'; age: number; static say(): void { console.log(this.name1) } constructor(age: number) { this.age = age } } let jielun = new Boy(45) // jielun.say() console.log(Boy.say())
4、类类型接口
定义一个接口,声明一个类去实现(implements)接口,注意不是继承 如下:
interface Person { name: string, age: number, say: (m: string) => void } // 使用类实现这个接口 class Man implements Person { name: string; age: number; say(m: string): void { console.log(this.name) }; constructor(name: string, age: number) { this.name = name this.age = age } } let wangyucao = new Man('小明', 10);
5、抽象类
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口, 抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类 内部定义抽象方法。
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 abstract关键字。
// 1. 特点 抽象类不能实例化 // 2. 抽象方法 不能写具体实现,必须在子类中写具体实现 abstract class Animal { name: string; age: number; constructor(m: string, n: number) { this.name = m this.age = n } abstract run(): string } class Cat extends Animal { constructor(m: string, n: number) { super(m, n) } run(): string { return `${this.name}在跑步` } } let huahua = new Cat('花花', 5) console.log(huahua)
八、泛 型
定义:先定义一个变量代表传入的类型,再使用该变量,因此,它是一种特殊的变量,只代表传入的数据类型,不是一个固定的值,而是传什么是什么,而这种类型变量称之为泛型
// 普通函数1 const fn = (x:number)=>{ console.log(x) } // 普通函数2 const fn2 = (x:string)=>{ console.log(x) } // 普通函数调用 fn(1) fn2('123') //使用泛型定义简化上述方式 function fn<T>(x: T): T { return x }
1、泛型在接口中的使用
interface fn1 <T>{ (m: T): T } let f2: fn1 = function (m: any): any { return `` }
2、泛型在类中的使用
class obj1<T>{ arr: T[] = []; push(m: T) { this.arr.push(m) } } let obj = new obj1() obj.push('及时雨宋江') obj.push('黑旋风李逵') obj.push('智多星吴用') obj.push('豹子头林冲') obj.push(100) obj.push(true)
3、泛型约束
type a = string | number | boolean // 泛型加约束条件 class obj1<T extends a>{ arr: T[] = []; push(m: T) { this.arr.push(m) } } let obj = new obj1() obj.push('及时雨宋江') obj.push('黑旋风李逵') obj.push('智多星吴用') obj.push('豹子头林冲') obj.push(100) obj.push(true)
4、泛型数组2种方式
interface Array<T>{ [name:number]:T } let arr3: Array<object> = [ { name: "朱德", age: 60 }, { name: "彭德怀", age: 60 }, { name: "林彪", age: 66 } ] // 第二种方式 interface newArr<T> { [name: number]: T } let arr4: newArr<object> = [ { name: "刘伯承", age: 60 }, { name: "叶剑英", age: 60 }, { name: "徐向前", age: 66 } ]