TS接口
# TS接口
# 接口(Interface)是什么?
相比JavaScript,typescript中的接口(Interface
)是一个新的概念,首先来了解一下接口到底是什么?
接口声明(interface declaration
)是命名对象类型的另一种方式,它能将多个类型注解合并成一个类型注解。用来约束对象、函数、类的结构。
下面分别用接口约束不同类型变量的结构
# 约束对象的结构
对象作为函数的参数,使用接口进行约束
interface Person {
name: string;
sayHello(): void;
}
function fn(per: Person){
per.sayHello();
}
fn({name:'孙悟空', sayHello() {console.log(`Hello, 我是 ${this.name}`)}});
约束对象时还可以定义可选成员、只读成员、动态成员
interface Post {
title: string
content: string
subtitle?: string // 可选成员
readonly summary: string // 只读成员
[prop: string]: string // 动态成员 【可索引类型】
}
const hello: Post = {
title: 'yk',
content: 'ykjun nb',
summary: 'ykjun',
yk: 'ykyk'
}
hello.kk = 'kk'
# 【补充】可索引类型
不确定对象中属性的个数时,可以使用可索引类型的接口
可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型
比如:约束字符串数组
interface StringArr {
[index: number]: string
}
let stringArr: StringArr = ['a', 'b', 'c']
# 约束函数的结构
interface Add {
(a:number, b:number): number // 约束函数的类型结构
}
let add: Add = function(a,b){
return a + b
}
比如对象中有一个字段是一个函数,使用接口约束就比较方便
interface Obj {
name: string
add: Add
}
# 约束对象数组
interface List {
readonly id: string // 只读属性
name: string // 末尾可以用逗号,其实应该用分号,所以可以省略符号
sex?: string // 可选属性
[x: string]: any // 字符串索引签名,让List可以支持多个属性
}
interface Result {
data: List[]
}
function render(result: Result) {
result.data.forEach((value)=>{
console.log(value.id, value.name)
})
}
let result: Result = {
data: [
{ id: 1, name: 'YK', sex: 'male' },
{ id: 2, name: 'yk', phone: 1234 }
]
}
render(result)
# 接口与类
# 类可以实现接口
使用接口来约束类成员,使用implements
实现接口,约束类的属性和方法的类型。类实现接口,必须要实现接口定义所有的属性。接口只能约束类的公有成员,不能约束类的构造函数。
interface Human {
name: string
eat(): void
}
class Asian implements Human {
name: string
constructor(name: string) {
this.name = name
}
eat() {}
}
一个类还可以实现多个接口
interface Eat{
eat(food: string): void
}
interface Run{
run(distance: number): void
}
class Person implements Eat, Run {
eat(food: string):void{
console.log(`坐着吃饭: ${food}`)
}
run(distance: number) {
console.log(`直立行走:${distance}`)
}
}
class Animal implements Eat, Run {
eat(food: string):void{
console.log(`啃着吃: ${food}`)
}
run(distance: number) {
console.log(`爬行:${distance}`)
}
}
# 接口继承
对接口使用 extends
关键字允许我们有效的从其他声明过的类型中拷贝成员,并且随意添加新成员。接口也可以继承多个类型
interface Human {
name: string
eat(): void
}
interface Man extends Human {
run(): void
}
interface Child {
cry(): void
}
// 继承多个接口
interface Boy extends Man, Child {}
let boy: Boy = {
name: '',
run() {},
eat() {},
cry() {},
}
接口还可以继承类,相当于把类的成员抽象出来(只有类的成员结构,没有具体实现)
class Auto {
state = 1
private state2 = 0
}
// 接口继承类
interface AutoInterface extends Auto {
}
// 类实现接口
class C implements AutoInterface {
state = 1
}
类继承父类实现接口
class Bus extends Auto implements AutoInterface {
}
最后总结一下接口与类关系
- 接口之间可以相互继承,这样能够实现接口的复用
- 类之间可以相互继承,可以实现属性和方法的复用
- 类可以实现接口,接口只能约束类的公有成员
- 接口可以继承类的成员,包括公有、私有和受保护成员
# 接口与抽象类的区别
抽象类做为其它派生类的基类使用,它们一般不会直接被实例化,不同于接口,抽象类可以包含成员的实现细节
# 接口与类型别名
类型别名和接口非常相似,大部分时候,你可以任意选择使用。接口的几乎所有特性都可以在 type
中使用,两者最关键的差别在于类型别名本身无法添加新的属性,而接口是可以扩展的。
# 扩展
// Interface
// 通过继承扩展类型
interface Animal {
name: string
}
interface Bear extends Animal {
honey: boolean
}
const bear = getBear()
bear.name
bear.honey
// Type
// 通过交集扩展类型
type Animal = {
name: string
}
type Bear = Animal & {
honey: boolean
}
const bear = getBear();
bear.name;
bear.honey;
# 添加新的属性
// Interface
// 对一个已经存在的接口添加新的字段
interface Window {
title: string
}
interface Window {
ts: TypeScriptAPI
}
const src = 'const a = "Hello World"';
window.ts.transpileModule(src, {});
// Type
// 创建后不能被改变
type Window = {
title: string
}
type Window = {
ts: TypeScriptAPI
}
// Error: Duplicate identifier 'Window'.
接口可能只会被用于声明对象的形状,不能重命名原始类型
// Here's two examples of
// using types and interfaces
// to describe an object
interface AnObject1 {
value: string
}
type AnObject2 = {
value: string
}
// Using type we can create custom names
// for existing primitives:
type SanitizedString = string
type EvenNumber = number
// This isn't feasible with interfaces
interface X extends string {
}
接口与类型别名的区别更多阅读:常见类型_TypeScript中文文档 (yayujs.com) (opens new window)