接口
接口声明引入新类型。接口是定义代码协定的常见方式。
任何一个类的实例只要实现了特定接口,就可以通过该接口实现多态。
接口通常包含属性和方法的声明
示例:
interface Style {
color: string // 属性
}
interface AreaSize {
calculateAreaSize(): number // 方法的声明
someMethod(): void; // 方法的声明
}
实现接口的类示例:
// 接口:
interface AreaSize {
calculateAreaSize(): number // 方法的声明
someMethod(): void; // 方法的声明
}
// 实现:
class RectangleSize implements AreaSize {
private width: number = 0
private height: number = 0
someMethod(): void {
console.log('someMethod called');
}
calculateAreaSize(): number {
this.someMethod(); // 调用另一个方法并返回结果
return this.width * this.height;
}
}
接口属性
接口属性可以是字段、getter、setter或getter和setter组合的形式。
属性字段只是getter/setter对的便捷写法。以下表达方式是等价的:
interface Style {
color: string
}
interface Style {
get color(): string
set color(x: string)
}
实现接口的类也可以使用以下两种方式:
interface Style {
color: string
}
class StyledRectangle implements Style {
color: string = ''
}
interface Style {
color: string
}
class StyledRectangle implements Style {
private _color: string = ''
get color(): string { return this._color; }
set color(x: string) { this._color = x; }
}
接口继承
接口可以继承其他接口,如下面的示例所示:
interface Style {
color: string
}
interface ExtendedStyle extends Style {
width: number
}
继承接口包含被继承接口的所有属性和方法,还可以添加自己的属性和方法。
泛型类型和函数
泛型类型和函数允许创建的代码在各种类型上运行,而不仅支持单一类型。
泛型类和接口
类和接口可以定义为泛型,将参数添加到类型定义中,如以下示例中的类型参数Element:
class CustomStack<Element> {
public push(e: Element):void {
// ...
}
}
要使用类型CustomStack,必须为每个类型参数指定类型实参:
let s = new CustomStack<string>();
s.push('hello');
编译器在使用泛型类型和函数时会确保类型安全。参见以下示例:
let s = new CustomStack<string>();
s.push(55); // 将会产生编译时错误
泛型约束
泛型类型的类型参数可以被限制只能取某些特定的值。例如,MyHashMap<Key, Value>这个类中的Key类型参数必须具有hash方法。
interface Hashable {
hash(): number
}
class MyHashMap<Key extends Hashable, Value> {
public set(k: Key, v: Value) {
let h = k.hash();
// ...其他代码...
}
}
在上面的例子中,Key类型扩展了Hashable,Hashable接口的所有方法都可以为key调用。
泛型函数
使用泛型函数可编写更通用的代码。比如返回数组最后一个元素的函数:
function last(x: number[]): number {
return x[x.length - 1];
}
last([1, 2, 3]); // 3
如果需要为任何数组定义相同的函数,使用类型参数将该函数定义为泛型:
function last<T>(x: T[]): T {
return x[x.length - 1];
}
现在,该函数可以与任何数组一起使用。
在函数调用中,类型实参可以显式或隐式设置:
// 显式设置的类型实参
last<string>(['aa', 'bb']);
last<number>([1, 2, 3]);
// 隐式设置的类型实参
// 编译器根据调用参数的类型来确定类型实参
last([1, 2, 3]);
泛型默认值
泛型类型的类型参数可以设置默认值。这样可以不指定实际的类型实参,而只使用泛型类型名称。下面的示例展示了类和函数的这一点。
class SomeType {}
interface Interface <T1 = SomeType> { }
class Base <T2 = SomeType> { }
class Derived1 extends Base implements Interface { }
// Derived1在语义上等价于Derived2
class Derived2 extends Base<SomeType> implements Interface<SomeType> { }
function foo<T = number>(): T {
// ...
}
foo();
// 此函数在语义上等价于下面的调用
foo<number>();
最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。