# 接口

在Typescript里，接口的作用就是为这些类型命名和为你的代码或者第三方代码定义契约。

```javascript
interface LabelType {
    label: string;
}
function printLabel(labelObj: LabelType) {
    console.log(labelObj.label)
}
```

**可选属性**

```
interface Label {
    label: string;
    width?: number;
}
```

**只读属性**

```
interface Point {
    readonly x: string;
}

const a: Point = {x:'1'}

// cannot assign to 'x' because it is a read-only property.
a.x = '2';
```

**额外的属性检查**

```javascript
interface A {
    a?: string; // 注意是可选的属性
}
function f(arg: A) {

}

f({b:1})  // error
```

即对象字面量会被特殊对待而且会经过*额外属性检查*,当将他们赋值给变量作为参数传递时，如果对象字面量存在任何“目标类型”不包含的属性时，将会得到一个错误。

在本例中，属性`b`不存在于目标类型`A`中。

如何绕开检查:\
1\. 类型断言

```
f({b:1} as A)
```

1. 字符串索引签名

   ```
   interface A {
    a?: string;
    [propKey:string]: any;
   }
   ```

   这里表示的是, A 可以有任意数量的属性。 &#x20;

**函数类型**\
接口除了描述带有属性的普通对象外，还可以描述函数类型:

```
interface Fun {
    (source:string, subString: string): boolean
}

let myFun: Fun;
myFun = function (s1, s2) {
    return s1 > s2
}
```

**可索引类型**

```
interface StringArray {
    [key: number]: string;
}
let myArray: StringArray;
myArray = ['1','2']
```

TypeScript支持两种索引签名，字符串和数字，但是*数字索引的返回值必须是字符串索引返回值类型的子类型*。

```
class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}
interface NotOkay {
    // error, 数字索引返回Animal，不是字符串索引Dog的子类型
    [x: number]: Animal;
    [x: string]: Dog;
}

interface NotOkay {
    // right, 数字索引返回 Dog，是字符串索引 Animal 的子类型
    [x: string]: Animal;
    [x: number]: Dog;
}
```

字符串索引签名会确保所有属性与其返回值类型匹配。

```javascript
interface NumberDictionary {
    [key: string]: number,
    length: number;
    name: string  //  error
}
```

上述例子要求当key为字符串时，返回值必须为number类型，而 `name` 不符合

**类类型**

强制类去符合某种契约

```javascript
// 要求类的实例必须有 currentTime 属性，以及 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) {}
}
```

**类静态部分与实例部分的区别**

```javascript
// 构造器签名
interface ClockConstructor {
    new (hour: number, minute: number);
}

class Clock implements ClockConstructor {
    currentTime: Date;
    constructor(h: number, m: number) { }
}
```

当一个类实现一个接口时，只能对`实例的部分`进行类型检查，constructor存在于`类的静态部分`，不在类的检查范围内。

**继承接口**

```
interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square = <Square>{};  // 同时有 color 属性和 sideLength 属性
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;
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yes-1-am.gitbook.io/blog/typescript-yu-fa/jie-kou.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
