TS学习第二节(接口)

225 阅读3分钟

 TypeScript的核心原则之一是对值所有结构进行类型检查。

function printLabel(labelledObj: { label: string}){
    console.log(labelledObj.label);
}
let myObj = { size: 10, label: "size 10 object"};
printLabel(myObj);

下面用接口重写上面的例子:

interface LabelledValue{
    label: string;
}
function printLabel(labelledObj: LabelledValue){
    console.log(labelledObj.label);
}

可选属性

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.are = config.width * config.width;
    }
    return newSquare;
}
let mySquare = createSquare({color: "black"});

可选属性的好处是:

  1. 可以对存在的属性进行预定义;
  2. 可以捕获引用了不存在的属性时的错误。

只读属性

一些对象属性只能在刚创建的时候修改其值,可以使用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>类型,它与Array<T>相似,只是把所有可变方法去掉了,可以确保数组创建后不能再被修改:

let a: number[] = [1, 2, 3];
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。

函数类型

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): boolean{
    let result = src.search(sub);
    return result > -1;
}

可索引的类型

与使用接口描述函数类型差不多,我们也可以描述那些能够通过索引得到的类型,比如a[10]或ageMap["daniel"]。可索引类型具有一个索引签名,它描述了索引的类型,还有相应的索引返回值类型。

interface StringArray{
    [index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: String = myArray[0];

可以将索引签名设置为只读,这样就防止了给索引赋值:

interface ReadonlyStringArray{
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; //error

类类型

实现接口

在接口里描述一个方法,在类里实现它,如下setTime方法:

interface ClockInterface{
    currentTime: Date;
    setTime(d: Date);
}
class Clock implements ClockInterface{
    currentTime: Date;
    setTime(d: Date){
        this.currentTime = d;
    }
    constructor(h: number, m: number){   }
}

继承接口

和类一样,接口也可以相互继承:

interface Shape{
    color: string;
}
interface Square extends Shape{
    sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;

一个接口可以继承多个接口,创建出多个接口的合成接口

interface Shape{
    color: string;
}
interface PenStroke{
    penWidth: number;
}
interface Square extends Shape, PenStroke{
    sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

混合类型

一个对象可以同时作为函数和对象使用,并带有额外的属性。

interface Counter{
    (start: number): string;
    interval: number;
    reset(): void;
}
function getCounter(): Counter{
    let counter = <Counter>function(start: number){ };
    counter.interval = 123;
    counter.reset = function(){ };
    return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;