TypeScript学习笔记
扎实基础,赶紧上手开发
第一、基础类型
-
boolean true/false
-
number 所有的数字都是浮点数,类型为number
-
string
-
Array Array<其他数据类型>
数据类型[]
-
tuple 元素数量和类型已知的数组,各元素的类型不必相同
[类型1,类型2,类型......]
Let x : [string,number]
-
enum(枚举类)
-
any 开发过程中不知道当前对象的类型,或者仅仅知道一部分数据类型时。可以使用any类,any类使当前代码通过编译阶段的类型检查!
-
Void 与any相反,Void表示没有任何类型,一般用于没有返回值的函数的类型声明
-
Null和Undefined 当指定了--structNullCheck的时候,null和undefined只能复制给void和他们各自,没有指定时,可以是任何类型的子类型
-
never 永不存在的值的类型,是任何类型的子类型,可以赋值给任何类型,除了never本身以外没有其他任何类型可以赋值给never类,any也不可以。
// 返回never的函数必须存在无法达到的终点 function error(message: string): never { throw new Error(message); } // 推断的返回值类型为never function fail() { return error("Something failed"); } // 返回never的函数必须存在无法达到的终点 function infiniteLoop(): never { while (true) { } }
-
object
第二、类型断言
有时候程序员比编译器更加清楚当前对象的类型,因此ts中引入类型断言,程序员用代码显式指定当前对象的类型,有点类似其他语言的强制类型转换,但是ts中的类型断言不进行检查和解构。
程序员显式地将某一个对象按照指定的类型进行处理
-
第一种形式——尖括号语法
let someValue:any = "this is a string"; let strLength:number = (<string>someValue).length;
-
as语法
let someValue:any = "this is a string!"; let strLength:number = (someValue as string).length;
第三、接口
typescript的核心原则之一就是对某一个对象所具有的结构要能够追踪检查,接口的作用就是对这些结构进行显示约束
定义接口的语法与定义类的语法类似。关键字为interface,一个简单的接口如下:
普通属性接口
interface LabelledValue{ label:string } //labelledObj是参数名,通过冒号符加接口,指定该参数需要满足的特征为 //1.必须具有label属性 //2.label属性必须时string function printLabel(labelledObj:LabelledValue){ console.log(labelledObj.label) }
需要注意的是,typescript编译器对于接口普通属性的检测并不关心检测对象属性的先后顺序,也不关心对象中是否引用了其他的属性。
其他接口分类以及语法:
可选属性接口
在:
符之前使用?
符号进行说明,表示该属性为可选属性。
可选属性的两个用途:
-
允许接口里的属性并不全部必须的,有些只有在某些条件下才存在
-
编译器能够捕获引用了未声明属性的错误
interface box{ width?: number; color?: string; } function area(square:box){ console.log(square.color); ... }
typescript对于参数是否满足接口的检查的规则比较严格,对于需要满足上面定义的box
接口的参数的函数,下边的对象box1
传入会导致报错。
class box1{ width:100; colour:"red"; } area(box1);//报错!!!Error:Property 'color' does not exist in type 'box1'
理论上,对象box1
具有width属性,没有color属性,接口box
定义的width和color都是可选属性,因此box1
应该满足接口box
的类型检查,但是typescript编译器对box1
检查时会进行报错,是因为box1
具有接口中没有声明的colour属性。
解决这种情况的办法有两种:
-
使用类型断言
class box1{ width:100; colour:"red"; } area(box1 as box);
-
额外属性声明
interface box( width?: number; color?: string; [proName: string]:any;//加上额外属性声明,允许对象引用除可选属性以外的其他属性 ) function area(square:box){ console.log(square.color); ... }
只读属性
一些睡醒只有在对象刚刚创建的时候能够赋值,这样的属性在接口中的定义语法是在属性名前加readonly
interface Point{ readonly x: number; readonly y: number; } let p1:Point=(x:10;y:20); p1.x=5;//赋值报错,属性x为只读属性,不能赋值
readonly与const的选择:
用作属性使用readonly
用作变量使用const
函数类型接口
众所周知,js对象部可以定义函数作为方法进行使用,因此接口的定义中必然会存在函数类型属性,函数类型属性的定义语法,我们需要给接口定义一个调用签名,具体的格式是一个只有参数列表和返回值类型的函数定义。如下:
interface SearchFunc{ (source:string,subString:string):boolean; }
使用:
let mySearch:SearchFunc; mySearch = function(source: string,substring:string){ let result = source.search(substring); return result>-1; }
同时函数类型接口可以使用关键字new,用来实现构造功能。
可索引类型接口
与使用接口描述函数类型类似,我们也可以描述那些能够通过索引得到的类型,如a[10]
,dict['attr']
,定义的语法也与描述函数的语法类似。
interface StringArray{ [index:number]:string;//方括号[]里边声明index,外面声明返回的类型 } let myArray:StringArray; myArray=['Bob','Fred']; let myStr:string=myArray[0];
javascript支持做索引index
的类型有两种:number和string,但是数字索引的返回值必须是字符串索引的子类型,因为当使用number来索引时,js会将number先转换成string再去进行索引查找。
class Animal { name: string; } class Dog extends Animal { breed:string; } interface NotOkay { [x:number]:Animal; [x:string]:Dog; } //报错,原因是number做索引返回超类Animal,string做索引反而返回子类Dog
类类型接口
ts的接口也可以显示地去约束一个类满足某种条件,类类型属性的声明与普通属性的声明类似。
interface ClockInterfade{ currentTime: Date;//类中的某个属性约束 setTime(d:Date);//类中的某个方法约束 } class Clock implements ClockInterface{//类接口的使用,implements currentTime:Date; constructor(...[props]){...} }
值得注意的是,类接口的约束检查只对类的公有部分进行检测,不会检测类是否具有某些私有成员。
private关键字声明私有属性,私有属性只能在本身类内进行访问,不可以在子类和实例中访问
protected关键字声明保护属性,保护属性可以在本身和子类中访问,不能在任何实例中访问。
继承接口(接口继承extends)
和类一样,接口也可以互相继承,继承接口让我们能够从一个接口里复制成员到另一个接口里去,可以更灵活地将接口分割到可以重用的模块中
interface Shape{ color:string; } interface Square extends Shape { sideLength:number; } let square = <Square>{}; square.color = "blue";//Square从Shape接口中继承而来的属性 square.sideLength = 10;
混合类型接口
接口能够描述js中丰富的类型,因为js动态灵活的特点,有时候你会希望一个对象可以同时具有以上提到的多种类型。例如,一个对象可以同时作为函数和对象使用,并带有额外的属性。对这样的对象进行接口编写就需要用到混合类型接口。
interface Counter{ (start:number):string; interval:number; reset():void; } function getCounter():Counter{ let counter =<Counter>function(start:number){}; counter.interval = 1233; counter.reset = function(){}; } let c = getCounter(); c(10); c.reset(); c.interval = 5.0;
接口继承类
当一个接口继承一个类类型,它会继承类的成员但不包括其实现。就好像接口声明了所有类中存在的成员,但是没有提供具体实现一样,接口同样会继承到几口的private和protected成员。这意味着当你创建了一个接口继承了一个拥有私有成员(包括属性和方法)或者受保护成员时,这个接口只能被这个类或者这个类的子类所实现impletements。
class Control { private state: any; } //要求SelectablControl具有state属性 interface SelectableControl extends Control{ select():void; } //正确,Button类派生自Control类,因此具有state属性 class Button extends Control implements SelectableControl { select(){}; } class TextBox extends Control{ select(); } //Error,Image没有state属性 class Image implements SelctableControl { select(); } class Location{ }
$\color{redOrange}{未完待续}$