Qual é a diferença entre 'extends' e 'implements' no TypeScript

Respostas:

153

Versão curta

  • extends significa:

A nova classe é uma criança . Ele obtém benefícios provenientes da herança. Ele tem todas as propriedades e métodos como pai. Ele pode sobrescrever alguns deles e implementar novos, mas o material pai já está incluído.

  • implements significa:

A nova classe pode ser tratada como a mesma "forma" , embora não seja uma criança . Pode ser passado para qualquer método em que Personseja necessário, independentemente de ter um pai diferentePerson

Mais ...

Em OOP (linguagens como C #, Java) , usaríamos

extendslucrar com a herança (ver wiki ). Citação pequena:

... Herança na maioria das linguagens orientadas a objetos baseadas em classes é um mecanismo no qual um objeto adquire todas as propriedades e comportamentos do objeto pai. A herança permite aos programadores: criar classes que são construídas sobre classes existentes ...

implementsserá mais para polimorfismo (veja wiki ). Citação pequena:

... polimorfismo é o fornecimento de uma única interface para entidades de diferentes tipos ...

Portanto, podemos ter uma árvore de herança realmente diferente da nossa class Man.

class Man extends Human ...

mas se também declararmos que podemos fingir ser um tipo diferente - Person:

class Man extends Human 
          implements Person ...

.. então podemos usá-lo em qualquer lugar, onde Personfor necessário. Nós apenas temos que cumprir as Pessoas "interface" (ou seja, implementar todas as suas coisas públicas) .

implementoutra classe? Isso é muito legal

A cara legal do Javascript (um dos benefícios) é o suporte integrado à digitação Duck ( consulte a wiki ). Citação pequena:

"Se ele anda como um pato e grasna como um pato, então deve ser um pato."

Então, em Javascript, se dois objetos diferentes ... tivessem um método semelhante (por exemplo render()), eles podem ser passados ​​para uma função que o espera:

function(engine){
  engine.render() // any type implementing render() can be passed
}

Para não perder isso - podemos fazer o mesmo em Typescript - com mais suporte de digitação. E é aí que

class implements class

tem seu papel, onde faz sentido

Em linguagens OOP como C#... nenhuma maneira de fazer isso ...

Além disso, a documentação deve ajudar aqui:

Interfaces estendendo classes

Quando um tipo de interface estende um tipo de classe, ele herda os membros da classe, mas não suas implementações. É como se a interface tivesse declarado todos os membros da classe sem fornecer uma implementação. As interfaces herdam até mesmo os membros privados e protegidos de uma classe base. Isso significa que, ao criar uma interface que estende uma classe com membros privados ou protegidos, esse tipo de interface só pode ser implementado por essa classe ou uma subclasse dela.

Isso é útil quando você tem uma grande hierarquia de herança, mas deseja especificar que seu código funcione apenas com subclasses que possuem certas propriedades. As subclasses não precisam ser relacionadas, além de herdar da classe base. Por exemplo:

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// Error: Property 'state' is missing in type 'Image'.
class Image implements SelectableControl {
    private state: any;
    select() { }
}

class Location {

}

Por enquanto

  • extends significa - obtém tudo de seu pai
  • implementsneste caso, é quase como implementar uma interface. O objeto filho pode fingir que é pai ... mas não obtém nenhuma implementação
Radim Köhler
fonte
quando você diz " extends- obtém tudo de seu pai", isso se aplica a membros privados? Por exemplo class Person {private name: string} class man extends Person{gender: string;}, mantem o nome da propriedade?
davejoem
Privados também estão lá. Apenas inacessível pelo TS. Torne-os protegidos e você poderá usá-los. No caso de “implementos” apenas a parte pública faz sentido. Espero que ajude um pouco
Radim Köhler
Excelente resposta. Só não tenho certeza por seu comentário para "privado está lá, mas não acessível por TS". Você quer dizer que as propriedades privadas são copiadas nesse objeto filho recém-criado? E no caso de implementos, apenas os bens públicos são copiados?
kushalvm
Além disso, resolvi mais um ponto. Se esta for a definição de estende. Então, por favor, se você pudesse explicar isto stackoverflow.com/questions/60390454/…
kushalvm
96

Em typescript (e em algumas outras linguagens OO), você tem classes e interfaces.

Uma interface não tem implementação, é apenas um "contrato" de quais membros / método esse tipo possui.
Por exemplo:

interface Point {
    x: number;
    y: number;
    distance(other: Point): number;
}

As instâncias que implementam esta Pointinterface devem ter dois membros do tipo number: xand y, e um método distanceque recebe outra Pointinstância e retorna a number.
A interface não implementa nenhum desses.

As classes são as implementações:

class PointImplementation implements Point {
    public x: number;
    public y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    public distance(other: Point): number {
        return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
    }
}

( código no playground )

Em seu exemplo, você trata sua Personclasse uma vez como uma classe ao estendê-la e uma vez como uma interface ao implementá-la.
Seu código:

class Person {
    name: string;
    age: number;
}
class Child  extends Person {}

class Man implements Person {}

Tem um erro de compilação dizendo:

A classe 'Man' implementa incorretamente a interface 'Person'.
A propriedade 'nome' está ausente no tipo 'Homem'.

E isso porque as interfaces carecem de implementação.
Então, se você implementuma classe, você apenas pega seu "contrato" sem a implementação, então você precisará fazer isso:

class NoErrorMan implements Person {
    name: string;
    age: number;
}

( código no playground )

O ponto principal é que, na maioria dos casos, você deseja extendoutra classe e não implementela.

Nitzan Tomer
fonte
7
Essa resposta é mais simples de entender.
Akshay Raut de
6

Ótima resposta de @nitzan-tomer! Me ajudou muito ... Eu estendi um pouco sua demonstração com:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

E como eles se comportam em funções que esperam um IPointtipo.

Portanto, o que aprendi até agora e tenho usado como regra geral: se você estiver usando classes e métodos que esperam tipos genéricos, use interfaces como os tipos esperados. E certifique-se de que o pai ou a classe base usa essa interface. Dessa forma, você pode usar todas as subclasses daquelas, na medida em que implementam a interface.

Aqui está a demonstração estendida

andzep
fonte
Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos de um autor, deixe um comentário abaixo de sua postagem. - Da avaliação
aronisstav
1
@aronisstav Eu só postei uma demonstração estendida do que encontrei uma boa resposta que já me ajudou. Mas talvez outra pessoa ache útil o trabalho que fiz ao estender a demonstração. Isso é tudo. Os comentários não têm o objetivo de colocar um bloco de código, então é por isso que acho melhor compreensível em um post de resposta. Qual é o problema disso?
andzep
Sua resposta foi (automaticamente?) Sinalizada devido ao tamanho e conteúdo, apareceu na minha fila de revisão e dei mérito aos motivos apresentados na sinalização. Sua principal contribuição (explicando que você estendeu a demonstração) seria melhor como um comentário. Com o parágrafo adicionado, talvez seja realmente mais útil.
aronisstav
@andzep, seu exemplo de demonstração estendida é realmente útil.
namit
3
  1. Interface estende interface com forma
  2. Interface estende classe com forma
  3. A classe implementa a interface deve implementar todos os campos fornecidos pela interface
  4. Classe implementa classe com forma
  5. A classe estende a classe com todos os campos

extendsfoco em herdar e implementsfoco na restrição sejam interfaces ou classes.

lei li
fonte
0

Estende implementos VS

  • extends: A classe filha (que é estendida) herdará todas as propriedades e métodos da classe é extends
  • implements: A classe que usa a implementspalavra - chave precisará implementar todas as propriedades e métodos da classe que elaimplements

Para colocar em termos mais simples:

  • extends: Aqui você obtém todos esses métodos / propriedades da classe pai para que não precise implementá-los sozinho
  • implements: Aqui está um contrato que a turma deve seguir. A classe deve implementar pelo menos os seguintes métodos / propriedades

Exemplo:

class Person {
  name: string;
  age: number;

  walk(): void {
    console.log('Walking (person Class)')
  }

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
class child extends Person { }

// Man has to implements at least all the properties
// and methods of the Person class
class man implements Person {
  name: string;
  age: number

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  walk(): void {
    console.log('Walking (man class)')
  }

}

(new child('Mike', 12)).walk();
// logs: Walking(person Class)

(new man('Tom', 12)).walk();
// logs: Walking(man class)

No exemplo, podemos observar que a classe filha herda tudo de Person, enquanto a classe man tem que implementar tudo da própria Person.

Se tivéssemos de remover algo da classe man, por exemplo, o método walk, obteríamos o seguinte erro de tempo de compilação :

A classe 'man' implementa incorretamente a classe 'Person'. Você quis dizer estender 'Person' e herdar seus membros como uma subclasse? A propriedade 'walk' está ausente no tipo 'man', mas é necessária no tipo 'Person'. (2720)

Willem van der Veen
fonte