接口
接口可以在面向对象编程中表示行为的抽象,也可以描述对象的形状。 接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。 (接口中不能含有具体的实现逻辑)
接口可以被实现、被继承, type不能。
type可以写联合类型
接口可以描述对象
interface Obj {
a: number,
b: number
}
const sum = (obj: Obj): number => obj.a + obj.b
sum({a: 1, b:2})
- 接口一方面可以在面向对象编程中表示为行为的抽象,另外可以用来描述对象的形状
- 接口就是把一些类中共有的属性和方法抽象出来,可以用来约束实现此接口的类
- 一个类可以继承另一个类并实现多个接口
- 接口像插件一样是用来增强类的,而抽象类是具体类的抽象概念
一个类可以实现多个接口,一个接口也可以被多个类实现,但一个类的可以有多个子类,但只能有一个父类
interface中可以用分号或者逗号分割每一项,也可以什么都不加
对象的形状
//接口可以用来描述`对象的形状`,少属性或者多属性都会报错
interface Speakable{
speak():void;
name?:string;//?表示可选属性
}
let speakman:Speakable = {
speak(){},//少属性会报错
name,
age//多属性也会报错
}
行为的抽象
//接口可以在面向对象编程中表示为行为的抽象
interface Speakable{
speak():void;
}
interface Eatable{
eat():void
}
//一个类可以实现多个接口
class Person implements Speakable,Eatable{
speak(){
console.log('Person说话');
}
eat(){}
}
class TangDuck implements Speakable{
speak(){
console.log('TangDuck说话');
}
eat(){}
}
同名的接口可以写多个,类型会自动合并:
interface A {
name: string;
}
interface A {
age: number
}
const obj: A = {
name: 'f',
age: 18
};
任意属性
//无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]:any`,propName名字是任意的
interface Person {
readonly id: number;
name: string;
[propName: string]: any;
}
let p1 = {
id:1,
name:'f',
age:10
}
接口的继承
- 一个接口可以继承自另外一个接口
interface Speakable {
speak(): void
}
interface SpeakChinese extends Speakable {
speakChinese(): void
}
class Person implements SpeakChinese {
speak() {
console.log('Person')
}
speakChinese() {
console.log('speakChinese')
}
}
readonly
有时我们只希望对象中的某些属性在创建的时候被赋值,之后就不能再修改了,这个时候我们可以在接口中给这个属性添加readonly
。用readonly
定义只读属性可以避免由于多人协作或者项目较为复杂等因素造成对象的值被重写。
```typescript interface Person{ readonly id:number; name:string } let p:Person = { name:’zhufeng’ }interface Person{
readonly id:number;
name:string
}
let p:Person = {
id :1,
name:'zhufeng'
}
// 这里会报错,因为 id 属性为只读属性,不能再被修改了
p.id = 1; // error TS2540: Cannot assign to 'id' because it is a read-only property.
<a name="RX2yy"></a>
# 函数类型接口
对方法传入的参数和返回值进行约束
```typescript
interface Discount {
(price: number): number
}
const discount: Discount = (price: number): number => price * 0.8;
可索引接口
- 对数组和对象进行约束
- userInterface 表示index的类型是 number,值的类型必须是 string
- UserInterface2 表示:index 的类型是 string,值的类型必须是 string ```typescript interface UserInterface {
}
let arr: UserInterface = [‘1’, ‘2’];
interface UserInterface2 {
} let obj: UserInterface2 = { 1: ‘1’, 2:’2’ };
<a name="sOuG6"></a>
# 类接口
类接口可以对类的进行约束:
```typescript
interface Speak {
name: string,
speak(): void
}
class Person implements Speak {
name!: string;
// Class 'Person' incorrectly implements interface 'Speak'.Property 'speak' is missing in type 'Person' but required in type 'Speak'.
speak() { }
eat() {}
}
上面的例子中,如果我们在 Person
类中没有实现 speak
方法会报错。
构造函数的类型
- 在 TypeScript 中,我们可以用 interface 来描述类
- 同时也可以使用 interface 里特殊的 new() 关键字来描述类的构造函数类型 ```typescript interface Person { // 不加new是修饰函数的,加new是修饰类的 new(name:string):Person } class Person { constructor(public name:string) {} }
function personFactory(clazz: Person, name: string) { return new clazz(name); }
const p = personFactory(Person, ‘f’); console.log(p); // {name: ‘f’}
我们写一个类的时候会得到两个类型,一个是构造函数的函数类型,另一个是类的实例类型。
```typescript
class Person { }
// 实例类型
const p1: Person = new Person();
// 构造函数类型的函数类型
const p2: typeof Person = Person;
注意:上述代码的 typeof
是 TS 中的,不是 JS 中的,我们可以用它来获取一个变量或对象的类型
const obj = {name: 'f', age: 18};
const b: typeof obj = 1;
上述代码会报错,我们把鼠标放到变量 b
上面,从提示框可以看到如下内容:
可以看到 b 需要赋值一个具有 name 和 age 属性的 对象。
接口使用,其他常见的情况:
interface A {
// 函数
(name: string): any,
// 这样写,是给函数加一个属性
age: number
}
interface B {
// 对象的一个属性
speak:()=>void
}
const a: A = (name: string) => '';
a.age = 18;
const b: B = {
speak() { }
};
抽象类 VS 接口
- 不同类之间公有的属性或方法,可以抽象成一个接口(Interfaces)
- 而抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
- 抽象类本质是一个无法被实例化的类,其中能够实现方法和初始化属性,而接口仅能够用于描述,既不提供方法的实现,也不为属性进行初始化
- 一个类可以继承一个类或抽象类,但可以实现(implements)多个接口
- 抽象类也可以实现接口 ```typescript abstract class Person { name!: string; abstract speak(): void; constructor(name:string) { this.name = name; };
} interface Eat { eat():void }
class F extends Person implements Eat { eat() { console.log(‘eat’) } speak() { console.log(‘speak’) } } const f = new F(‘f’); f.speak(); f.eat(); ```
接口和类型别名的区别
不同点:
- 扩展语法: interface使用extends,type使用‘&’
- 同名合并:interface 支持,type 不支持。
- 描述类型:对象、函数两者都适用,但是 type 可以用于基础类型、联合类型、元祖。
- 计算属性:type 支持计算属性,生成映射类型,;interface 不支持。
相同点:
- 两者都可以用来描述对象或函数的类型
- 两者都可以实现继承