简体   繁体   中英

Why a object interface define is similar to class interface define in typescript

I am pretty new to typescript, when I learn it from its playground with the interface part, there is one confuse:

http://www.typescriptlang.org/Handbook#interfaces-our-first-interface-

http://www.typescriptlang.org/Handbook#interfaces-class-types

One is talking about how to define interface of object, one is define for class, but they can use similar structure, could anyone point out why?

interface of object, one is define for class, but they can use similar structure, could anyone point out why

An object has no runtime knowledge of a creator . Whereas a class instance knows about its constructor. This is shown below:

interface Foo {
    foo: number
}

let foo: Foo = { foo: 123 };

class Bar {
    bar: number;
}

let bar: Bar = new Bar(); 
bar.bar = 123;
console.log(bar instanceof Bar); // True  

That doesn't change the fact that typescript is structural https://basarat.gitbook.io/typescript/content/docs/getting-started.html

Also classes can provide greater structure to your code :https://basarat.gitbook.io/typescript/content/docs/classes.html

In both cases the Interface serves the same purpose - to apply a type restriction/refinement. There is no difference between an "interface for an object" and an "interface for (or applied to) a class".

The first example shows Structural Typing without introducing the concept of a class:

Any type that has a type-conforming structure fulfills the Interface contract 1 .

.. Notice we didn't have to explicitly say that the [anonymously created] object we pass to 'printLabel' implements this interface like we might have to in other languages. Here, it's only the shape that matters. If the object we pass to the function [can be statically proven to meet] the requirements listed [in the Interface], then it's allowed .

An instance of a Class that implements an Interface implicitly guarantees this contract. Adding the Interface to the Class allows additional constraint checks to be done at the class declaration itself instead of only at usage-sites: this enables more localized and useful type-related error reporting.


1 This is a static/compilation restriction: the type information of the object has been automatically synthesized from the object literal itself. The actual runtime value is irrelevant to proving the type-correctness.

They have similar structure but they are used in different ways. The class allows you to create new objects to be used in your application. Where the interface tells the compiler how thing should be structured. Below you can see that you can add a value to the label property. You can not do this with the interface.

interface Something {
    label: string;
}

class Something {
    label: string = 'some string value';
}

In the example below the interface enforces the Something class to always need a property named label and the type needs to be a string . If you change the type or remove the property all together. The compiler will complain.

interface ISomething {
    label: string;
}

class Something implements ISomething {
    label: string = 'some string value';
}

In the example above I recommend using the convention of adding a capital I in front of your interface names to eliminate confusion between classes and interfaces.


In the next example we'll use an interface ( IUser ) to allow the serveral classes to be passed into the getUserDescription function without the compiler complaining. This is called Polymorphism. Our function doesn't care if it is a Teacher or a Student or any other class. All it cares about is that the structure being passed in matches the interface.

interface IUser {
    firstName: string;
    lastName: string;
    type: string;
}

class Student {

    firstName: string = null;
    lastName: string = null;
    type: string = 'student';
    courses: Array<any> = [];

    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

class Teacher implements IUser {

    firstName: string = null;
    lastName: string = null;
    type: string = 'teacher';
    classes: Array<any> = [];

    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

const getUserDescription = (user: IUser): string => {
    return `${user.firstName} ${user.lastName} is a ${user.type}`;
};

getUserDescription(new Teacher('Harry', 'Jones')); // Harry Jones is a teacher
getUserDescription(new Student('Joe', 'Cool')); // Joe Cool is a student

If you notice above Teacher implements IUser but Student does not. You normally you would have both done in the same way but I wanted to show that you can enforce the structure at the class level or not.

Checkout my article http://www.codebelt.com/typescript/typescript-classes-object-oriented-programming/ for more info.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM