layaBox---TypeScript---接口
Posted 格拉格拉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了layaBox---TypeScript---接口相关的知识,希望对你有一定的参考价值。
目录
1.接口示例
TypeScript核心原则之一是对值所具有的结构进行类型检查。被称作“鸭式辫型法”或“结构性子类型化”。
function printLable( lableObj: lable:string )
console.log( lableObj.lable );
let myObj = size:10, lable:"Size 10 object" ;
printLable( myObj );
接口示例:
interface LableValue
lable: string;
function printLable( lableObj: LableValue )
console.log( lableObj.lable );
let myObj = size:10,lable:"size 10 object";
printLable( myObj );
⚠️注意:类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。
2.可选属性
接口里的属性不全是必须的,有些只在某些条件下存在,或者根本不存在。
带有可选属性的接口与普通接口的定义差不多,只是在可选属性名字定义后加一个?符号。
好处:
1。可以对可能存在的属性进行预定义。
2. 可以捕获引用了不存在的属性时的错误。
例:
interface SquareConfig
color?: string;
width?: number;
function createSquare( config:SquareConfig):color:string, area:number
let newSquare = color:"white", area:100;
if(config.color)
newSquare.color = config.color;
if(config.width)
newSquare.area = config.width * config.width;
return new Square;
let mySquare = createSquare(color:"black");
3.只读属性
接口:
//一些对象属性只能在对象刚创建的时候修改其值,可以在属性名前 用 readonly 来指定只读属性
interface Point
readonly x: number;
readonly y: number;
//可以通过赋值来构造一个Point,赋值后 x、y 再也不能被改变了。
let p1:Point = x:10, y:20 ;
p1.x = 5; //error
数组:
TypeScript具有ReadonlyArray<T>类型,确保数组创建后再也不能被修改。
let a:number[] = [1,2,3,4];
let ro: ReadonlyArray<number> = a;
ro[0]= 12; //error
ro.push(5); //error
ro.length = 100; //error
a = ro; //error
上面的最后一行可以看到,把整个ReadonlyArray赋值给一个普通数组也是不可以的。
但是可以用’类型断言‘重写:
a = ro as number[];
⚠️注意:readonly 与 const 的区别:
作为变量使用时用const, 作为属性使用时用readonly
4.额外的属性检查
我们在第一个例子里使用了接口,TypeScript让我们传入size: number; lable: string到仅期望得到lable: string; 的函数里。 我们也学过了可选属性。
然而,当你天真的将这两者结合的话就会像javascript里那样搬起石头砸自己的脚。
//拿createSquare例子来说
interface SquareConfig
color?: string;
width?: number;
function createSquare( config: SquareConfig ):color: string, area: number
//...
let mySquare = createSquare( coor:"red", width: 100 );
注意⚠️:这里传的是coor 而不是 color, 在js中这会默默的失败。然而ts会认为这段代码可能存在bug.
对象字面量会被特殊对待 且 会经过额外属性检查,当它们赋值给变量或作为参数传递时,如果一个对象字面量存在任何‘目标类型’不包含的属性时,你会得到一个Error
//error: 'coor' not expected in type 'SquareConfig'
let mySquare = createSquare( coor: "red", width: 100 );
想要绕开这些检查非常简单,最简单的方式就是使用类型断言:
let mySquare = createSquare( width:100, opacity:0.5 as SquareConfig );
然而最佳的避开方式是添加一个字符串索引签名,前提是你能够确定这个对象具有某些作为特殊用途的额外属性。
//如果SquareConfig带有上面定义的类型的color和width属性,并且还会带有任意数量的其它属性,那么我们可以这样定义它:
inteface SquareConfig
color?: string;
width?: number;
[propName: string]: any;
这样SquareConfig就可以带有任意数量的属性,并且只要它们不是color和width ,那么就无所谓它们的类型是什么。
还有一种可以避开额外属性检查的方式:将这个对象赋值给另一个变量。
let squareOption = coor:"red", width:100 ;
let mySquare = createSquare(squareOption);
5.函数类
接口可以描述函数类型
为了使用接口表示函数类型,我们需要给接口定义一个调用签名。参数列表里的每个参数都需要名字和类型
interface SearchFunc
(source: string, subString: string): boolean;
这样定义后,我们可以像使用其它接口一样使用这个函数类型都接口。
例:
let mySearch:SearchFunc;
mySearch = function(source:string, subString:string)
let result = source.search(subString);
return result > -1;
对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。
let mySearch:SearchFunc;
mySearch = function(src:string, sub:string)
let result = src.search(sub);
return result > -1;
函数的参数会逐个进行检查,要求对应位置上的参数类型上兼容的。如果你不想指定类型,TS的类型系统会根据返回值推断出参数类型。
6.可索引的类型
与使用接口描述函数类型差不多,我们也可以描述那些能够“通过索引得到”的类型,比如a[10]或ageMap["daniel"].
//可索引类型具有一个 索引签名, 它描述了对象索引的类型。还有相应的索引返回值类型
interface StringArray
[index:number]: string
let myArray: StringArray;
myArray = ["Bob","Fred"];
let myStr: string = myArray[0];
这里,我们定义了StringArray接口,它具有索引签名。
这个索引签名表示了当用 number去索引StringArray时会得到string类型的返回值
ts支持2种索引签名:字符串 和 数字。
可以同时使用2种类型的索引,但是数字索引的返回值必须是字符串索引返回值的子类型。
这是因为当使用number来索引时,js会将它转换成string 然后再去索引对象。
也就是说用 数字100 去索引 等同于用 字符串“100”去索引,因此两者要保持一致。
//将索引签名设置为只读,这样就可以防止了给索引赋值:
interface ReadonlyStringArray
readonly [index:number]:string;
let myArray:ReadonlyStringArray = ["Alice","Bob"];
myArray[2] = "Mallory"; //error. 因为索引签名上只读的,所以不能设置
7.类类型
7.1.实现接口
//1.与C#或java里的接口一样,ts也能用它来明确的强制一个类去符合某种契约。
interface ClockInterface
currentTime: Date;
class Clock implements ClockInterface
currentTime: Date;
constructor(h: number, m: number)
//2.也可以在接口中描述一个方法,在类里实现它。
interface ClockInterface
currentTime: Date;
setTime(d: Date);
class Clock implements ClockInterface
currentTime: Date;
setTime(d: Date)
this.currentTime = d;
constructor(h:number, m:number)
7.2类静态部分与实例部分的区别
类具有2个类型: 静态部分的类型 和 实例的类型。
当一个类实现了一个接口时,只对其实例部分进行类型检查。
因此我们应该直接操作类的静态部分,
例:
interface ClockConstructor
new (hour:number, minute:number): ClockInterface;
interface ClockInterface
tick();
function createClock(ctor:ClockConstructor, h: number, m: number ):ClockInterface
rerurn new ctor(h, m);
class DigitalClock implements ClockInterface
constructor(h:number, m: number)
tick()
console.log("beep beep");
let digital = createClock(DigitalClock,7,32);
8.继承接口
//和类一样,接口也可以相互继承。
interface Shape
color: string;
interface Square extends Shape
sideLength: number;
let square = <Square>;
square.color = "red";
square.sideLength = 10;
//一个接口也可以继承多个接口,创建出多个接口的合成接口。
interface Shape
color: string;
interface PenStroke
penWidth: number;
interface Square extends Shape,PenStroke
sideLength: number;
let squ = <Square>;
squ.color = "blue";
squ.penWidtg = 5.0;
squ.sideLength = 10;
9.混合类型
例: 一个对象可以同时作为函数和对象使用,并带有额外的属性。
interface Counter
(start: number): string;
interval: number;
reset(): void;
function getCounter(): Counter
let cter = <Counter> function( start: number );
cter.interval = 125;
cter.reset = function();
return cter;
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
在使用js第三方库时,你可能需要像上面这样去完整的定义类型
10.接口继承类
当接口继承了一个类类型时,它会继承类的成员但不包括其实现。
接口同样会继承到类的private和protected成员。 也就意味着,当你创建了一个接口继承了一个拥有私有或保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)
//类
class Control
private state: any;
//接口继承类
interface SelectableControl extends Control
select(): void;
//类继承类 再实现接口
class Button extends Control implements SelectableControl
select()
//类继承类
class TextBox extends Control
select()
//error "Image"类型缺少“state”属性
class Image implements SelectableControl
select()
上面的例子中 selectableControl 包含了Control的所有成员,包括私有成员 state。
因为state是私有成员,所以只有Control的子类才能实现SelectableControl接口。
以上是关于layaBox---TypeScript---接口的主要内容,如果未能解决你的问题,请参考以下文章