• Chinese version of TypeScript Tutorial – Project introduction
  • TypeScript Tutorial Chinese version – Section 0. preface
  • TypeScript Tutorial Chinese version – Section 1. An introduction to
  • TypeScript Tutorial Chinese version – Section 2. Basic types of
  • TypeScript Tutorial Chinese version – Section 3. Control flow statement
  • TypeScript Tutorial Chinese – Section 4. function
  • TypeScript Tutorial Chinese version – Section 5. class
  • TypeScript Tutorial Chinese version – Section 6. interface
  • TypeScript Tutorial Chinese version – Section 7. High-level types
  • TypeScript Tutorial Chinese version – Section 8. The generic
  • TypeScript Tutorial Chinese version – Section 9. The module
  • Chinese version of TypeScript Tutorial – Section 10.node.js

Section 6. Interface

interface

The original address

In this tutorial, you’ll learn about TypeScript interfaces and how to use them to perform type checking.

Interfaces in TypeScript

Interfaces in TypeScript specify constraints in code and provide explicit names for type checking. Let’s start with a simple example:

function getFullName(person: { firstName: string; lastName: string }) {
  return `${person.firstName} ${person.lastName}`;
}

let person = {
  firstName: 'John'.lastName: 'Doe'};console.log(getFullName(person));
Copy the code

Output:

John Doe
Copy the code

In this example, the TypeScript compiler checks the arguments passed to getFullName(). If the arguments have two string attributes, firstName and lastName, it can pass TypeScript type checking; otherwise, it will throw an error.

It is clear from the code that the type comments for function parameters make our code difficult to read. To solve this problem, TypeScript introduces the concept of interfaces.

Here we define a Person interface that has two properties of type string:

interface Person {
  firstName: string;
  lastName: string;
}
Copy the code

By convention, interface names are humped, with uppercase letters separating words in names such as Person, UserProfile, and FullName.

Once the Person interface is defined, you can use it as a type, or you can use it to comment function arguments:

function getFullName(person: Person) {
  return `${person.firstName} ${person.lastName}`;
}

let john = {
  firstName: 'John'.lastName: 'Doe'};console.log(getFullName(john));
Copy the code

The code is now much easier to read than before.

The getFullName() function takes as an argument any object with two string attributes of type firstName and lastName, and it does not need to have exactly those two attributes, as shown below, defining an object with four attributes:

let jane = {
  firstName: 'Jane'.middleName: 'K.'
  lastName: 'Doe'.age: 22
};
Copy the code

Since the Jane object has two string attributes, firstName and lastName, you can pass it into getFullName() as follows:

let fullName = getFullName(jane);
console.log(fullName); // Jane Doe
Copy the code

Optional attribute

Interfaces can have optional attributes. To declare an optional attribute, you add (?) after the attribute name. Symbol, as follows:

interface Person {
  firstName: string; middleName? :string;
  lastName: string;
}
Copy the code

In this example, the Person interface has two required attributes and one optional attribute. The following example demonstrates how the Person interface can be used in the getFullName() function:

function getFullName(person: Person) {
  if (person.middleName) {
    return `${person.firstName} ${person.middleName} ${person.lastName}`;
  }
  return `${person.firstName} ${person.lastName}`;
}
Copy the code

Read-only property

If the property can be modified only when the object is created, you can prefix the property name with the readonly keyword:

interface Person {
  readonly ssn: string;
  firstName: string;
  lastName: string;
}

let person: Person;
person = {
  ssn: '171-28-0926'.firstName: 'John'.lastName: 'Doe'};Copy the code

In this example, the SSN attribute cannot be modified:

person.ssn = '171-28-0000';
Copy the code

Error message:

error TS2540: Cannot assign to 'ssn' because it is a read-only property.
Copy the code

Function types

In addition to describing properties of objects, interfaces can also describe function types. To describe function types, you need to assign interfaces to the following form:

  • Contains a parameter list of types
  • Include return types

As follows:

interface StringFormat {
  (str: string.isUpper: boolean) :string;
}
Copy the code

Now you can use this function-type interface. Here’s how to declare and assign a value to a variable that has a function type:

let format: StringFormat;

format = function (str: string, isUpper: boolean) {
  return isUpper ? str.toLocaleUpperCase() : str.toLocaleLowerCase();
};

console.log(format('hi'.true));
Copy the code

Output:

HI
Copy the code

Note that parameter names do not need to match the parameter names in the function signature. The following example is equivalent to the above example:

let format: StringFormat;

format = function (src: string, upper: boolean) {
  return upper ? src.toLocaleUpperCase() : src.toLocaleLowerCase();
};

console.log(format('hi'.true));
Copy the code

The StringFormat interface ensures that all function callers that implement it pass in the required parameters: a string parameter and a Boolean parameter.

The following code also works fine, even though lowerCase doesn’t have a second argument:

let lowerCase: StringFormat;
lowerCase = function (str: string) {
  return str.toLowerCase();
};

console.log(lowerCase('Hi'.false));
Copy the code

Notice that the second argument is passed when the lowerCase() function is called.

Class types

If you’ve ever used Java or C#, you’ll see that the main purpose of interfaces is to define conventions between unrelated classes. For example, the following Json interface can be implemented by any unrelated class:

interface Json {
  toJSON(): string;
}
Copy the code

Here we declare a class that implements the Json interface:

class Person implements Json {
  constructor(private firstName: string.private lastName: string) {}
  toJson(): string {
    return JSON.stringify(this); }}Copy the code

In the Person class we implement the toJson() method of the Json interface.

The following example demonstrates how to use the Person class:

let person = new Person('John'.'Doe');
console.log(person.toJson());
Copy the code

Output:

{"firstName":"John"."lastName":"Doe"}
Copy the code

summary

  • Interfaces specify constraints in code and also provide explicit names for type checking;
  • Interfaces can have many optional and read-only attributes;
  • Interfaces can be used as function types;
  • Interfaces are often used as class types to establish conventions between unrelated classes.

Extension interface

The original address

In this tutorial, you will learn how to extend interfaces so that you can copy properties and methods from one interface to another.

An interface that extends an interface

Suppose we have an interface named Mailable that contains the send() and queue() methods:

interface Mailable {
  send(email: string) :boolean;
  queue(email: string) :boolean;
}
Copy the code

Then you have a number of classes that already implement the Mailable interface. Now you want to add a new method to the Mailable interface that says it will delay sending mail, as follows:

later(email: string.after: number) :void
Copy the code

Adding the later() method directly to the Mailable interface will break the current code and cause incompatibility issues. To avoid this problem, you can create a new interface to extend the Mailable interface:

interface FutureMailable extends Mailable {
  later(email: string.after: number) :boolean;
}
Copy the code

Use the extends keyword to extend an interface with the following syntax:

interface A {
  a(): void;
}

interface B extends A {
  b(): void;
}
Copy the code

Interface B extends interface A with two methods A () and B (). Like classes, the FutureMailable interface inherits the Send () and queue() methods from the Mailable interface.

The following example demonstrates how to implement the FutureMailable interface:

class Mail implements FutureMailable {
  later(email: string.after: number) :boolean {
    console.log(`Send email to ${email} in ${after} ms.`);
    return true;
  }
  send(email: string) :boolean {
    console.log(`Sent email to ${email} after ${after} ms. `);
    return true;
  }
  queue(email: string) :boolean {
    console.log(`Queue an email to ${email}. `);
    return true; }}Copy the code

An interface that extends multiple interfaces

An interface can extend multiple interfaces, creating a combination of all interfaces, as shown below:

interface C {
  c(): void;
}

interface D extends B, C {
  d(): void;
}
Copy the code

In this example, interface D extends interfaces B and C, so interface D has all the methods of interfaces B and C: a(), B (), and C () methods.

Interfaces that extend classes

TypeScript allows interfaces to extend classes. In this case, interfaces inherit class properties and methods. Additionally, interfaces can inherit private and protected members of a class, not just public members. This means that when an interface extends a class that has private members and protected members, the interface can only be implemented in the class that the interface extends or a subclass of that class.

By doing this, you can limit the use of the interface to the class or subclass of that class from which the interface inherits. If you try to implement the interface from a class or subclass of that class that does not inherit from the interface, an error message will be thrown:

class Control {
  private state: boolean;
}

interface StatefulControl extends Control {
  enable(): void;
}

class Button extends Control implements StatefulControl {
  enable(){}}class TextBox extends Control implements StatefulControl {
  enable(){}}class Label extends Control {}

// Error: cannot implement
class Chart implements StatefulControl {
  enable(){}}Copy the code

summary

  • Interfaces can extend one or more existing interfaces;
  • Interfaces can also extend classes. If a class contains private or protected members, the interface can only be implemented by that class or a subclass of that class.