一,简介
- TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准。
- TypeScript 由微软开发的自由和开源的编程语言。
- TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。
- TypeScript 扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译
说了这么多,其实get到的信息,typescript是javascript的一个超集。但是,通过typecript学习,我们还知道:typescript 在完整保留 JavaScript 运行时行为的基础上,通过引入静态类型系统来提高代码的可维护性,减少可能出现的 bug。
二,主要内容
- 下面我用思维导图,绘制typescript的主要内容(因人而异哈)
三,起步
-
1,类型系统 因为typescript的一大特点就是:类型。相比于javascript来说,它多了类型约束。这样做的目的,是为了在运行前就对代码进行检测,保证了代码的质量性,可维护性等。
-
2,静态类型 JavaScript是动态类型,因为是在运行时,才会对语法进行检测,如果有错误时,卡在当前错误处,阻止下面的代码运行。 typescript则不同,它在编译阶段就开始对语法进行检测,如果有错误,马上就提示。这就是静态类型。
-
3,弱类型 我们知道,JavaScript是弱类型语音,其实typescript是完全兼容JavaScript语言的。它不会修改JavaScript运行时的特性。因此也属于弱类型。
-
4,核心设计理念 在完整保留 JavaScript 运行时行为的基础上,通过引入静态类型系统来提高代码的可维护性,减少可能出现的 bug。
-
5,安装
npm install -g typescript
或者 yarn add -g typescript
//检测是否安装成功:
tsc -v
- 6,第一个typescript程序
这是因为 TypeScript 只会在编译时对类型进行静态检查,如果发现有错误,编译的时候就会报错。而在运行时,与普通的 JavaScript 文件一样,不会对类型进行检查。
但是 TypeScript 编译的时候即使报错了,还是会生成编译结果,我们仍然可以看到编译后的js文件,也没有语法错误。这个可以打印一下对应的js文件,即可验证。
- 7,关于运行typescript代码(不用webpack等工具),关于vscode运行typescript可参考
四,基础
-
1,原始数据类型
- boolean
let isOk:boolean = false //编译通过 let isFine:boolean = new Boolean(0) //编译不通过,这是因为:使用构造函数Boolean 创造的对象不是 布尔值 // new Boolean()返回的是一个对象
- number
let n1:number = 123 let n2:number = NaN //编译通过 结果为 var n1 = 123 var n2 = NaN
- string
let name:string = 'zhangsan' let age:string = 24 //编译 name通过,但是在age,不通过。因为类型约束为 string //编译结果都是正确的 在开始我们也讨论过 详情查看hello typescript介绍 var name = 'zhangsan' var age = 24
- null 和 undefined typescript中,null 和 undefined来定义原始数据类型。也就是说,undefined 和 null 是所有类型的子类型。
let a1:undefined = undefined let a2:null = null // 可以赋值给 string类型的变量: let str1:string = undefined //编译通过 let num1:number = null //编译通过
- 在typescript中,void表示空值,不返回任何类型
let n:void let num:number = n //编译不通过 因为 void不是所有类型的子类型,不像null 和 undefined function people():void{ console.log('hello world') }
-
2,任意值
- 在typescript中,any表示任意值类型。 变量声明的时候,没有声明类型,默认为any
let p:any = 'zhangsan' let n:any = 123 n = '123' let a:any = [] let b=true // 默认为any //编译结果: var p = 'zhangsan' var n = 123 n='123' var a =[] var b = true //像这样的,类型指定为any,可以是任意类型的。 //如果,是一个普通类型,那么在赋值过程中改变类型是不允许的。
-
3,类型推论
- 如果在声明的时候,没有明确的指定类型,那么typescript会按照类型推论的规则推断出一个类型。
let a = 'lisi' a = 20 //编译报错,myts.ts:24:1 - error TS2322: Type 'number' is not assignable to type 'string'.
类型推论,得到的是:
let a:string = 'lisi' a = 20 //所以,会编译报错
但是,如果在定义的时候,没赋值:都会被推断any类型而完全不被类型检查
let b; b='wangwu' b=20 //可以看出,编译成功 // 定义的时候,没有赋值,不管之后有没有赋值,都会被推断any类型而完全不被类型检查
-
4,联合类型
- 声明类型的时候,可以声明多个。用 | 分割
let somethings:string | number somethings ='ABCD' somethings = 24 //编译成功,结果为 var somethings somethings= 'ABCD' somethings = 24
但是,在赋值时,不属于该声明的类型:
let somethings:string | number somethings ='ABCD' somethings = false //编译出错,但是编译结果(正确)为: var somethings somethings= 'ABCD' somethings = false
这个时候,会编译报错:
- 联合类型的方法:
function people(attrs:string|number):number{ return Math.ceil(attrs) } //报错
这个时候,编译也会报错:因为Math.ceil不是string 和 number 的共同属性
- 联合类型的属性:
let p1:string|number p1 = 'zhangsan' console.log(p1.length) // 8 p1 = 20 console.log(p1.length) //编译报错 // 因为类型 "number"不存在属性 "length"
这个时候,会编译报错:类型 "number"不存在属性 "length"
所以,访问联合类型的属性或者方法时,要兼顾类型的共有属性,才不会出现编译报错。
-
5,接口
- 接口是面向对象JavaScript程序员的工具箱中最有用的工具之一
- 在JavaScript中模仿接口主要有三种方式:通过注释、属性检查和鸭式辩型法(可以自行查看网上资料),以上三种方式有效结合,就会产生类似接口的效果。
- 此接口并非是,我们所说的前后端联调的接口。
- 在typescript中,使用interface来定义对象的类型。
下面举个简单的例子:
interface Dog{ name:string; color:string; age:number } let xiaohei:Dog = { name:'小黑', color:'black', age:2 } // 接口: 主要是是一种规范,一种约束。
使用 interface定义了一个Dog的接口,定义一个变量xiaohei,它的类型是Dog。
-
interface 定义了属性或者方法,在约束变量的时候,需要满足interface定义接口里所有的属性。
当少了一些属性:
interface Animal{ name:string; eat(str:string):void } class Dog implements Animal{ name:string; constructor(name:string){ this.name = name } // eat(){ // console.log(this.name+'在吃粮食') // } } var d = new Dog('小黑') d.eat() //编译报错,因为缺少interface定义接口中的eat方法 //所以,需要将eat()注释放开,这时编译成功
这个时候,编译报错:
当多一些属性时:
interface Dog{ name:string; color:string; } let xiaohei:Dog = { name:'小黑', color:'black', age:2 } //也是不允许的。这时编译也会报错
这个时候,编译报错:
-
6,可选属性
这个时候,我们想,可不可以不要完全匹配,定义接口的属性。
答案是有的 ,用关键字: ?
interface Dog1{ name:string; color:string; age?:number; } let xiaohei:Dog1 = { name:'小黑', color:'black' } //编译成功,未报错。可以看出,这时,用关键字?可以解决不完全匹配。即,可选属性
- 7,任意属性 我们希望,定义一个未知的属性。但是,目前我们不知道该属性名,请问支持吗?
答案是有的,用关键字[unknownName] 。 注意:unknownName是代表未知属性名,可随便定义。
interface Student{ name:string; age:number; [unknownName:string]:any; } let zhangsan:Student = { name:'zs', age:10, classNo:20, school:'一中' } //编译成功
当我们,把 [unknownName:string]:string。这时候:
interface Student{ name:string; age:number; [unknownName:string]:string; } let zhangsan:Student = { name:'zs', age:10, classNo:20, school:'一中' } //编译报错 // 类型"number"的属性"age"不能赋给字符串索引类型"string" // 不能将类型"number"分配给类型"string"
可以看出,任意属性一旦定义,那么确定属性和可选属性的类型都必选是它的类型的子集。
于是,可以结合联合属性:
interface Student{ name:string; age?:number; [unknownName:string]:string|number } let zhangsan:Student = { name:'zs', classNo:20, school:'一中' } //编译成功
- 8,只读属性 在javascirpt的表单中,我们可能不希望,别人修改表单的数据,于是我们可以设置,只读属性。
在typescript 中,同样存在只读属性。
interface Student{ readonly name:string; age?:number; [unknownName:string]:string|number } let zhangsan:Student = { name:'zs', classNo:20, school:'一中' } zhangsan.name ='lisi' //编译报错 // 无法分配到"name",因为它是只读属性
注意:【当Student的属性name设置了readonly时,在定义变量zhangsan的时候,name必须存在】
-
9,数组的类型
- 表示法一:( [类型+ 方括号] )
let arr:number[] = [1,2,3,4,5] //编译成功 let arr1:number[] =['1',2,3,4,5] //编译报错 : 不能将类型"string"分配给类型"number" //这是因为:我们定义了数组arr1的类型,是number,所以数组内的每一项必须是number arr.push('zs') //编译报错: 类型"string"的参数不能赋给类型"number"的参数 //这是因为: 向arr数组中添加了字符串'zs',不满足 每一项必须是number
- 表示法二:(泛型)
let a:Array<number> =[1,2,3,4,5] // 数组泛型 可以参考下节内容
- 表示法三:(接口表示法)
interface Student{ [index:number]:string } let zs:Student =['name','age','classno'] //编译成功
- any在数组中应用
let arr:any[] = ['zs',12,'一中']
-
10,函数的类型 (1)在typescript中,函数也有两种表示方式: 匿名函数和函数声明法
function a():string{ return '张三' } var f = function():number{ return 123 }
(2)在typescript中定义方法传参
function sum(x:number,y:number):number{ return x+y } var fsum2= function(x:number,y:number):number{ return x+y }
(3)在typescript中,方法的可选参数
// es5里面方法的实参和形参可以不一样。但是ts中必须一样,如果不一样就需要配置可选参数 function getInfo(name:string,age?:number):string{ if(age){ return `${name}---${age}` }else{ return `${name}---年龄保密` } } console.log(getInfo('zhangsan',123)) console.log(getInfo('lisi'))
(4)在typescript中,方法的默认参数
function sum(a:number,b:number=20):number{ return a+b } alert(sum(10)) //30 alert(sum(10,10)) // 20
(5)在typescript中,剩余参数法
// 三点运算符 接受形参传过来的值 function sum(...result:number[]):number{ var sum = 0; for(var i=0;i<result.length;i++){ sum+= result[i] } return sum } alert(sum(1,2,3,4)) // 10
(6)在typescript中,函数重载
java中方法的重载: 重载值得是两个或者两个以上同名函数,但是他们的参数不一样,这时会出现函数重载的情况。
typescript中的重载:通过为同一个函数提供多个函数类型定义来实现多种功能的目的
// es5 的重载 functin sum(a){ console.log('0000')} function sum(a,b){consle.log('1111')} //注意:[下面的函数会覆盖上面的函数。]
typescript 的重载
function getInfo(name:string):string; function getInfo(age:number):string; function getInfo( str:any):any{ if(typeof str==='string'){ return '我叫'+ str }else{ return '我的年龄'+ age } } alert(getInfo('张三')) // 我叫张三 //正确写法 alert(getInfo(20)) // 我的年龄 20 // 正确写法 alert(getInfo(true)) //错误写法
- 类型断言
简单来说就是先做好一个假设,使得编译通过。类型断言更像是类型的选择,而不是类型转换。
推荐以 as 方式,因为 jsx 这样的语法中只支持 as 方式。
function func(val: string | number): number { if (val.length) { return val.length } else { return val.toString().length } } //编译报错
因为 访问联合类型值的属性时,这个属性必须是所有可能类型的共有属性, 而length不是共有属性,val 的类型此时也没确定,所以编译不通过。
当我们使用类型断言:
function func(val:string|number):number{ if((val as string).length){ return (val as string).length }else{ return val.toString().length } } // 编译成功 // 把 val 断言为了 string类型,此时就可以访问 length 属性了
类型断言纯粹是一个编译时语法,同时也是一种为编译器提供关于如何分析代码的方法。
双重断言
- 任何类型都可以被断言为 any
- any 可以被断言为任何类型
function handler(event:Event){ const mouseEvent = event as MouseEvent }
然而,下面的例子
function handler(event:Event){ const mouseEvent = event as HTMLElement } //Error:'Event' 和 'HTMLElement' 中的任何一个都不能赋值给另外一个
如果继续使用那个类型,可以使用双重断言
先断言炒年糕兼容所有类型的any,再断言成想使用的类型:
function handler(event:Event){ const element =(event as any) as HTMLElement // ok }
五,结束
基础内容的这块笔记,暂且就这些。下一篇,开始是 typescript进阶内容 。
经常看到身边的小伙伴,总是说,又出新技术了,又迭代了,又整活了,真的学不动了,干不动了... meybe 学习的方式不对,心态不对。
多练,多读,多实践。慢慢进步,量变才能诱发质变。放好心态,加油吧!