TypeScript --- 接口(interface) 简单了解

108 阅读4分钟

介绍

TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

基本定义

interface Person {
    name: string,
    age: number
}

它代表了有一个name属性且类型为string的对象。 类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。

可选属性

interface Person {
    name?: string,
    age?: number
}

带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号。

只读属性

一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly来指定只读属性:

interface Point {
    readonly x: numebr,
    readonly y: number
}

你可以通过赋值一个对象字面量来构造一个Point。 赋值后, xy再也不能被改变了。

let p1: Point =  {x: 10, y: 20 };
p1.x = 5; // error

函数类型

接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。

为了使用接口表示函数类型,我们需要给接口定义一个调用签名。 它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。

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; 
}

函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的。 如果你不想指定类型,TypeScript的类型系统会推断出参数类型,因为函数直接赋值给了 SearchFunc类型变量。函数的返回值类型是通过其返回值推断出来的。如果让这个函数返回数字或字符串,类型检查器会警告我们函数的返回值类型与 SearchFunc接口中的定义不匹配。

let mySearch: SearchFunc; 
mySearch = function(src, sub) { 
    let result = src.search(sub); 
    return result > -1; 
}

可索引的类型

可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。

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

TypeScript支持两种索引签名:字符串和数字。 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用 number来索引时,JavaScript会将它转换成string然后再去索引对象。 也就是说用 100(一个number)去索引等同于使用"100"(一个string)去索引,因此两者需要保持一致。

interface NumberDictionary { 
    [index: string]: number; 
    length: number; // 可以,length是number类型 
    name: string // 错误,`name`的类型与索引类型返回值的类型不匹配 
}

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

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

类类型

实现接口

与C#或Java里接口的基本作用一样,TypeScript也能够用它来明确的强制一个类去符合某种契约。

可在接口里描述方法,在类里实现它

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 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;