Web-Typescript 接口

接口

        Typescript 接口与您在 C# 和 Java 中习惯的接口具有类似的用途,但它们具有非常不同的语义。在 C# 和 Java 中,接口主要用作实现该接口的类的模板。Typescript 类也可以用于此目的,但它们也可以被认为是 JavaScript 对象的模板。

        假设我们使用自动类型推断声明了以下 JavaScript 对象。

let me = { name:"Reza", age:21, address:"Gold Coast" };

        我们可以声明三个简单的 Typescript 接口来匹配这一点(还有更多可能)。

 interface Person1 { name:string; age: number;  address:string; } ;
 interface Person2 { name:string;  age: number; } ;
 interface Person3 { name:string; } ; 

        请注意此处使用分号 ';“(它不是逗号),最后一个属性后面有一个分号。

        这三个接口可以在原始对象声明中使用,如下所示。

let me1 : Person1 = { name:"Reza", age:21, address:"Gold Coast" };
let me2 : Person2 = { name:"Reza", age:21 };
let me3 : Person3 = { name:"Reza" };

        它们具有不同的类型检查含义。第一个将坚持初始化对象中存在所有三个属性。第二个声明只会坚持两个属性,第三个声明只会坚持一个属性。这意味着以下声明将无法通过Typescript检查。

  let me1 : Person1 = { name:"Reza", age:21 };
  let me2 : Person2 = { name:"Reza", age:21, hieght:92.5};
  let me3 : Person3 = { name:"Reza", hieght:123};

        这组 TypeScript 代码出错的原因如下:

  1. 在第一个代码行中,变量 me1 定义为类型 Person1,但它缺少接口 Person1 中定义的属性 address
  2. 在第二个代码行中,变量 me2 定义为类型 Person2,但它包含额外的属性 hieght,而接口 Person2 并未定义该属性。
  3. 在第三个代码行中,变量 me3 定义为类型 Person3,但它缺少接口 Person3 中定义的属性 hieght

        在上述每种情况下,其中一个接口成员不存在,或者用于初始化变量的对象中存在额外的元素。

        虽然接口在对象初始化中的使用方式很严格,但当接口用作函数参数时,这种情况会发生变化。该行为类似于 C# 或 Java 中的多态行为。请考虑以下函数定义,该定义使用上述 Person3 接口来定义参数:

let pname = function(n:Person3):string {
    return n.name;
  }

        以下调用都是正确的:

console.log(pname(me1));
console.log(pname(me2));
console.log(pname(me3));

        Typescript 对象还允许我们指定可选属性。这与我们在上一节中看到的可选参数具有类似的语法。上述接口示例的以下变体允许年龄和地址属性是可选的。

扫描二维码关注公众号,回复: 17354018 查看本文章
interface Person4 { name:string; age?: number; address?:string; } ;
let me4:Person4 = { name: "Reza"}; // OK
let me5:Person4 = { name: "Reza", age:21}; // OK

        Typescript 对象还允许我们指定可选属性。这与我们在上一节中看到的可选参数具有类似的语法。上述接口示例的以下变体允许年龄和地址属性是可选的。

interface Person4 { name:string; age?: number; address?:string; } ;
let me4:Person4 = { name: "Reza"}; // OK
let me5:Person4 = { name: "Reza", age:21}; // OK

        要确定是否提供了可选属性,我们可以使用 if 语句。例如,以下函数检查年龄和地址属性是否存在,如果不存在,则插入一个值。

function fillPerson (p:Person4): Person1 {
    let newp:Person1 =
      {name: "", age:10, address: "No fixed address"};
    newp.name = p.name;
    if (p.age) { // optional property present
      newp.age=p.age;
    }
    if (p.address) { // optional property present
      newp.address=p.address;
    }
    return newp;
  }

        接口的另一个特点是我们可以将成员指定为只读。与变量一样,这意味着接口属性只能在初始化具有接口的对象时更新,并且 Typescript 将在任何其他时间显示错误。

        例如,我们可以将后续示例中的 name 属性设为只读:

  interface Person5 { readonly name:string; age?: number; address?:string; } ;

        对于声明为具有接口 Person5 的任何对象,尝试更改 name 属性将导致 Typescript 语法错误。

        我们还可以声明函数接口和数组接口。这些与我们到目前为止看到的并不完全相同,因为它们通常仅适用于单个函数或单个数组(而不是具有多个属性的对象)。您可以将这些视为为函数类型或数组类型分配名称的一种方式。

        下面是函数接口声明的简单示例。

        这将使用具有两个数字参数并返回一个数字的任何函数正确键入 check。请注意,接口中的参数名称不必与实际函数定义中的名称匹配,我们之前看到的函数类型也是如此。

        可索引类型接口(例如数组)也可以类似地定义。例如,以下接口声明将针对任何数字数组(按数字索引)正确键入 check。

 interface NumArray {
    [index:number]: number;
  } 

        请注意,可索引类型也可以由其他类型(例如通过字符串)进行索引。例如,以下类型是可由字符串索引的数字数组:

 interface NumArray2 {
    [index:string]: number;
  } 

        对于这个数组,我们可以按任何字符串(与 C# 或 Java 非常不同)进行索引,例如:

  let a1:NumArray2 = {};
  a1["hippo"] = 23;
  console.log(a1["hippo"]);

        Typescript 类可以像其他语言一样实现接口。我们将等到我们看类后再演示。

        最后,接口也可以使用继承,就像你见过的其他语言一样。例如,我们可以声明一个名为 Animal 的接口,并将其扩展到包含 Animal 所有属性的 Pet 接口。

interface Animal {
    species: string;
  }
  interface Pet extends Animal {
    name: string;    // the species property is inherited to be part of this
  }

        如前所述,Typescript 接口与 C# 或 Java 相同,但在 Typescript 中有一些额外的应用程序。当接口与类一起使用时,您将熟悉它们。在 Typescript 中,它们也与 JavaScript 对象一起使用。

        请考虑以下 Typescript 接口定义:

  interface Student {ID:number; name: string; marks: number};

        请注意界面的各个部分是如何用分号 “;” 分隔的,而不是用逗号 “,” 与 JavaScript 对象一起使用的。

        我们可以利用这个接口来定义变量,以便 Typescript 将检查对象是否具有正确的形式。例如,以下对象变量具有正确和不正确的初始化:

  let s1:Student = {ID:1234, name: "Baz", marks: -1};
  let s2:Student = {ID:1234, name: "Baz" }; // error 'marks' is missing

        接口类型声明仅检查指定的元素,不能像使用其他语言的接口那样添加额外的元素。例如,以下内容是不正确的:

 interface Student2 {ID:number};
 let s3:Student2 = {ID:1234, name: "Baz", marks: -1}; // fails 

        当我们使用函数参数接口时,这种严格的行为不会反映出来。您的作者认为这不是很一致。使用上述接口考虑以下函数:

let getID = function (s:Student2) {
    return s.ID;
  }

        现在,看看 Student2 的定义,我们预计以下内容会失败,但它们是正确的。

        在这两种情况下,函数参数只需要一个具有 ID 属性的对象。注意 S6 甚至不使用接口来定义对象。这与上面解释的对文字对象的严格检查形成鲜明对比。

        我们还可以使用接口来防止对象属性的更改。这是通过只读关键字实现的。例如,我们可以将学生 ID 属性设为只读,这样如果我们尝试更改它,Typescript 会产生语法错误:

interface Student3 {
  readonly ID:number;
  name: string;
  marks: number
  };

        为了允许接口中的可选元素,有特定的语法。假设我们想使上述 Student 界面中的名称和标记属性可选。我们在标识符后用“?”符号指定:

interface Student4 {ID:number; name?:string; marks?: number;};

        然后,我们可以进行如下分配:

 let s7:Student4 = {ID:1234, name: "Baz"};
 let s8:Student4 = {ID:1234, marks: 23};
 let s9:Student4 = {ID:1234}; 

        我们还可以声明函数接口和数组接口。这些与我们迄今为止看到的那些不同。它们通常仅适用于单个函数或单个数组(不适用于具有多个属性的对象)。您可以将这些视为一种方式

        为函数类型或数组类型指定名称。

        下面是函数接口声明的简单示例。

interface BinNumFun {
    (n1:number, n2:number): number;
  }

        这将使用具有两个数字参数并返回一个数字的任何函数正确键入 check。请注意,接口中的参数名称不必与实际函数定义中的名称匹配,我们之前看到的函数类型也是如此。因此,要使用这种函数类型,我们只需使用符号 BinNumFun。

        可索引类型接口(例如数组)也可以类似地定义。例如,以下接口声明将针对任何数字数组(按数字索引)正确键入 check。

interface NumArray {
    [index:number]: number;
  }

        请注意,可索引类型也可以由其他类型(例如通过字符串)进行索引。例如,以下类型是可由字符串索引的数字数组:

interface NumArray2 {
    [index:string]: number;
  }

        对于这个数组,我们可以按任何字符串(与 C# 或 Java 非常不同)进行索引,例如

let a1:NumArray2 = {};
  a1["hippo"] = 23;
  console.log(a1["hippo"]);

        Typescript 类可以像其他语言一样实现接口。我们将等到我们看类后再演示。接口也可以像以前看到的那样使用继承。

猜你喜欢

转载自blog.csdn.net/qq_54813250/article/details/133578966