typescript定义bmap-TypeScript 套接字(接口)

TypeScript 套接字(接口

本节介绍 TypeScript 中各种类型套接字的声明和使用。 套接字在 TypeScript 中非常重要。 我们使用套接字来定义契约,例如类型命名、属性检测和函数类型定义。

学习完下一节的类后,您就会知道类也可以用作套接字。 套接字的类型有很多种,在学习过程中必须自己编译才能实现灵活使用。

1. MOOC 说明

TypeScript 的核心原则之一是对值的结构进行类型检查。 它有时被称为“鸭子类型”或“结构类型”。 在 TypeScript 中,套接字的作用是命名这些类型并为您的代码或第三方代码定义契约。 - 官方定义

socket是为了约束JavaScript本身的随机性。 通过定义socket,规定了变量、类、函数等应该以什么格式声明,从而达到多人协作的一致性。 TypeScript 编译器依赖套接字进行类型检查,并且套接字将在最终编译为 JavaScript 后被删除。

// 语法格式
interface DemoInterface {
}

2、应用场景

在声明对象、函数或类时,首先定义套接字,以保证其数据结构的一致性。

当多人协作时,定义套接字就显得尤为重要。

3、插座的好处

过去我们写JavaScript来定义一个函数:

function getClothesInfo(clothes) {
  console.log(clothes.price)
}
let myClothes = {
  color: 'black', 
  size: 'XL', 
  price: 98 
}
getClothesInfo(myClothes)

以前我们这样写JavaScript很正常,但同时你可能会遇到以下问题:

getClothesInfo() // Uncaught TypeError: Cannot read property 'price' of undefined
getClothesInfo({ color: 'black' }) // undefined

相信你也知道为什么,JavaScript是弱类型语言,不会对传入的参数进行任何检查,只有在运行时才会发现错误。 这样,通过定义socket,就可以在编译阶段甚至开发阶段避免这种错误的发生。 套接字将检查类型是否与某个结构匹配。

3.1 示例

下面以套接字的形式重绘了前面的示例:

案例展示

interface Clothes {
  color: string;
  size: string;
  price: number;
}
function getClothesInfo(clothes: Clothes) {
  console.log(clothes.price)
}
let myClothes: Clothes = { 
  color: 'black', 
  size: 'XL', 
  price: 98 
}
getClothesInfo(myClothes)

操作案例 点击“操作案例”查看在线操作效果

代码解释:代码中定义了一个socket Clothes,传入的变量clothes中,其类型为Clothes。 这样,传入对象的外观就被约束为与套接字定义一致。 只要传入的对象满足前面的类型约束,就是允许的。

尖端:

定义套接字的第一个字母应该小写。

你只需要关注值的外观,与其他语言不同,定义套接字是为了实现。

如果没有特殊说明,定义的变量不允许有比socket少的属性,也不允许有比socket多的属性。 当它是形参时,变量的形状必须与套接字的形状一致。

4. 套接字属性 4.1 可选属性

并非套接字中的所有属性都是必需的。 可选属性的含义是在定义变量时该属性可能不存在。

// 语法
interface Clothes {
  color?: string;
  size: string;
  price: number;
}
// 这里可以不定义属性 color
let myClothes: Clothes = { 
  size: 'XL', 
  price: 98 
}

具有可选属性的套接字与普通套接字定义类似,除了一个 ? 符号添加到可选属性名称子定义旁边。

此时仍然不允许添加未定义的属性。 如果引用了不存在的属性,TS将直接捕获错误。

4.2 只读属性

某些对象属性只能在对象刚刚创建时更改其值。 可以在属性名前使用 readonly 来指定只读属性,例如价格不能更改:

// 语法
interface Clothes {
  color?: string;
  size: string;
  readonly price: number;
}
// 创建的时候给 price 赋值
let myClothes: Clothes = { 
  size: 'XL', 
  price: 98 
}
// 不可修改
myClothes.price = 100
// error TS2540: Cannot assign to 'price' because it is a constant or a read-only property

TypeScript 可以通过 ReadonlyArray 将链表设置为只读,因此它的所有写入方法都将无效。

let arr: ReadonlyArray = [1,2,3,4,5];
arr[0] = 6; // Index signature in type 'readonly number[]' only permits reading

代码说明:代码中的类库句型稍后会专门章节介绍。

4.2.1 只读与const

确定是使用 readonly 还是 const 的最简单方法是将其用作变量或属性。 如果用作变量,则使用const,如果用作属性,则使用readonly。

4.3 任意属性

有时候我们希望socket允许任意属性typescript定义bmap,句型就是用[]包裹属性:

// 语法
interface Clothes {
  color?: string;
  size: string;
  readonly price: number;
  [propName: string]: any;
}
// 任意属性 activity
let myClothes: Clothes = { 
  size: 'XL', 
  price: 98,
  activity: 'coupon'
}

代码解释:这里的socket Clothes可以有任意多个属性,但只要不是colorsize和price,它们的类型是什么并不重要。

this.$axios({
  method: 'put',
  url: '/cms/user',
  data: {
    nickname: this.nickname,
  },
  showBackend: true,
})

5. 功能类型

除了用属性描述普通对象之外,套接字还可以描述函数类型。

为了让套接字代表函数类型,我们需要为套接字定义一个调用签名。 它就像一个只有参数列表和返回类型的函数定义。

interface SearchFunc {
  (source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string): boolean {
  return source.search(subString) > -1;
}

对于函数类型的类型检查,函数的参数名称不需要与套接字中定义的名称匹配。 您可以更改函数的参数名称,只要函数参数的位置保持不变即可。 函数的参数一一检查:

interface SearchFunc {
  (source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
// source => src, subString => sub
mySearch = function(src: string, sub: string): boolean {
  return src.search(sub) > -1;
}

如果不想指定类型,TypeScript 的类型系统将推断参数类型,因为函数直接参数化 SearchFunc 类型变量。

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

如果socket中的函数类型有函数名,则以下两种写法是等价的:

interface Calculate {
  add(x: number, y: number): number
  multiply: (x: number, y: number) => number
}

6. 可转位类型

可转位类型socket读起来有点生硬,直接看例子:

// 正常的js代码
let arr = [1, 2, 3, 4, 5]
let obj = {
  brand: 'imooc',
  type: 'education'
}
arr[0]
obj['brand']

让我们看一下定义可索引类型套接字:

interface ScenicInterface {
  [index: number]: string
}
let arr: ScenicInterface = ['西湖', '华山', '故宫']
let favorite: string = arr[0]

示例中,索引签名是数字类型,返回值是字符串类型。

另一个索引签名是字符串类型。 我们可以同时使用两种类型的索引,并且数字索引的返回值必须是字符串索引的返回值类型的子类型。 通过下面的例子来理解这句话:

// 正确
interface Foo {
  [index: string]: number;
  x: number;
  y: number;
}
// 错误
interface Bar {
  [index: string]: number;
  x: number;
  y: string; // Error: y 属性必须为 number 类型
}

代码解释:

第12行,句子类型错误是因为使用数字索引时,JavaScript会将其转换为字符串,然后对对象进行索引。 也就是说,使用100(一个数字)来索引相当于使用“100”(一个字符串)来索引,所以两者需要保持一致。

7. 班级类型

我们希望类的实现必须遵守socket定义,因此可以使用implements关键字来保证兼容性。

这种类型的socket在传统的面向对象语言中最为常见,比如java中的socket就是这些类类型的socket。 这些套接字类似于表象类,而套接字只能丰富表象方法和成员属性,而实现类必须实现套接字中的所有表象方法和成员属性。

interface AnimalInterface {
  name: string;
}
class Dog implements AnimalInterface {
  name: string;
  
  constructor(name: string){
    this.name = name
  }
}

您还可以在套接字中描述一个方法并在类中实现它:

interface AnimalInterface {
  name: string
  eat(m: number): string
}
class Dog implements AnimalInterface {
  name: string;
  constructor(name: string){
    this.name = name
  }
  eat(m: number) {
    return `${this.name}吃肉${m}分钟`
  }
}
 

套接字描述类的公共部分,而不是公共部分和私有部分。 它不会帮助您检测类是否有单独的私有成员。

8. 继承套接字

与类一样,套接字也可以通过关键字extent相互继承。 这允许我们将成员从一个套接字复制到另一个套接字,从而更灵活地将套接字拆分为可重用的模块。

interface Shape {
  color: string;
}
interface Square extends Shape {
  sideLength: number;
}
let square = {} as Square;
// 继承了 Shape 的属性
square.color = "blue";
square.sideLength = 10;

一个套接字可以继承多个套接字,创建多个套接字的复合套接字。

interface Shape {
  color: string;
}
interface PenStroke {
  penWidth: number;
}
interface Square extends Shape, PenStroke {
  sideLength: number;
}
let square = {} as Square;
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

9. 混合型

如上所述,套接字可以描述对象的函数、方法或对象的属性。

有时希望一个对象可以同时拥有其中提到的多种类型,例如一个对象可以作为函数,同时具有属性和技能。

interface Counter {
  (start: number): string;
  interval: number;
  reset(): void;
}
function getCounter(): Counter {
  let counter = function (start: number) { } as Counter;
  counter.interval = 123;
  counter.reset = function () { };
  return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

代码解释:

第 1 行声明一个套接字。 如果只有一个成员(start:number):string,那么这个socket就是一个函数socket,而且它还有另外两个成员,可以用来描述对象的属性和方法,从而形成一个Hybrid socket。

第 7 行创建一个 getCounter() 函数,其返回值是 Counter 类型。

let counter = function (start: number) { } as Counter;

第8行通过类型判断将函数对象转换为Counter类型。 转换后的对象不仅实现了对功能socket的描述,使其成为一个函数,而且还具有interval属性和reset()方法。 判断成功的条件是只要两种数据类型中的一种可以形式参数化为另一种,这里函数类型数据不能形式参数化为socket类型变量,因为它没有interval属性和reset()方法。

类型确定也将在后面的章节中单独介绍。

10. 总结

本节介绍socket的基本用法及其使用场景。 套接字在 TypeScript 中至关重要typescript定义bmap,TypeScript 编译器依赖套接字进行类型检测。