¿Cuál es la diferencia entre 'extiende' e 'implementa' en TypeScript?


Respuestas:


153

Version corta

  • extends medio:

La nueva clase es un niño . Obtiene beneficios que vienen con la herencia. Tiene todas las propiedades, métodos como padre. Puede anular algunos de estos e implementar nuevos, pero el material principal ya está incluido.

  • implements medio:

La nueva clase puede tratarse como la misma "forma" , mientras que no es un niño . Se podría pasar a cualquier método donde Personse requiera, independientemente de tener un padre diferente alPerson

Más ...

En OOP (lenguajes como C #, Java) usaríamos

extendspara beneficiarse de la herencia (ver wiki ). Pequeña cita:

... La herencia en la mayoría de los lenguajes orientados a objetos basados ​​en clases es un mecanismo en el que un objeto adquiere todas las propiedades y comportamientos del objeto padre. La herencia permite a los programadores: crear clases que se basan en clases existentes ...

implementsserá más por polimorfismo (ver wiki ). Pequeña cita:

... el polimorfismo es la provisión de una única interfaz a entidades de diferentes tipos ...

Entonces, podemos tener un árbol de herencia realmente diferente de nuestro class Man.

class Man extends Human ...

pero si también declaramos que podemos pretender ser de un tipo diferente - Person:

class Man extends Human 
          implements Person ...

.. entonces podemos usarlo en cualquier lugar, donde Personsea ​​necesario. Solo tenemos que cumplir con Persons "interface" (es decir, implementar todas sus cosas públicas) .

implementotra clase? Eso es realmente genial

La cara agradable de Javascript (uno de los beneficios) es el soporte integrado de la escritura Duck ( ver wiki ). Pequeña cita:

"Si camina como un pato y grazna como un pato, entonces debe ser un pato".

Entonces, en Javascript, si dos objetos diferentes ... tuvieran un método similar (por ejemplo render()), se pueden pasar a una función que lo espera:

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

Para no perder eso, podemos hacer lo mismo en TypeScript, con más soporte mecanografiado. Y ahí es donde

class implements class

tiene su papel, donde tiene sentido

En lenguajes de programación orientada a objetos como C#... no hay forma de hacer eso ...

Además, la documentación debería ayudar aquí:

Interfaces que amplían clases

Cuando un tipo de interfaz extiende un tipo de clase, hereda los miembros de la clase pero no sus implementaciones. Es como si la interfaz hubiera declarado a todos los miembros de la clase sin proporcionar una implementación. Las interfaces heredan incluso los miembros privados y protegidos de una clase base. Esto significa que cuando crea una interfaz que extiende una clase con miembros privados o protegidos, ese tipo de interfaz solo puede ser implementado por esa clase o una subclase de ella.

Esto es útil cuando tiene una jerarquía de herencia grande, pero desea especificar que su código funciona solo con subclases que tienen ciertas propiedades. Las subclases no tienen que estar relacionadas además de heredar de la clase base. Por ejemplo:

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 {

}

Entonces, mientras

  • extends significa - obtiene todo de su padre
  • implementsen este caso es casi como implementar una interfaz. El objeto hijo puede fingir que es padre ... pero no obtiene ninguna implementación

cuando dices " extends-tiene todo de su padre", ¿se aplica a los miembros privados? Por ejemplo, class Person {private name: string} class man extends Person{gender: string;}¿ mantiene el nombre de la propiedad?
davejoem

Los privados también están ahí. Simplemente inaccesible por TS. Hazlos protegidos y podrás usarlos. En el caso de "implementos", solo la parte pública tiene sentido. Espero que ayude un poco
Radim Köhler

Excelente respuesta. No estoy seguro por su comentario de "privado está ahí pero no es accesible para TS". ¿Quiere decir que las propiedades privadas se copian en ese objeto hijo recién creado? ¿Y en el caso de los implementos, solo se copian las propiedades públicas?
kushalvm

Además, obtuve un punto más. Si esta es la definición de extiende. Entonces, por favor, si pudiera explicar esto stackoverflow.com/questions/60390454/…
kushalvm

98

En mecanografiado (y algunos otros lenguajes OO) tienes clases e interfaces.

Una interfaz no tiene implementación, es solo un "contrato" de los miembros / método que tiene este tipo.
Por ejemplo:

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

Las instancias que implementan esta Pointinterfaz deben tener dos miembros de tipo número: xy y, y un método distanceque recibe otra Pointinstancia y devuelve un number.
La interfaz no implementa ninguno de esos.

Las clases son las implementaciones:

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 en el patio de recreo )

En su ejemplo, trata su Personclase una vez como una clase cuando la extiende y una vez como una interfaz cuando la implementa.
Tu codigo:

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

class Man implements Person {}

Tiene un error de compilación que dice:

La clase 'Man' implementa incorrectamente la interfaz 'Person'.
Falta la propiedad 'nombre' en el tipo 'Hombre'.

Y eso se debe a que las interfaces carecen de implementación.
Entonces, si eres implementuna clase, solo tomas su "contrato" sin la implementación, por lo que deberás hacer esto:

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

( código en el patio de recreo )

La conclusión es que en la mayoría de los casos desea extendotra clase y no a implementella.


7
Esta respuesta es más sencilla de entender.
Akshay Raut

6

¡Gran respuesta de @ nitzan-tomer! Me ayudó mucho ... Amplié un poco su demo con:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

Y cómo se comportan en funciones que esperan un IPointtipo.

Entonces, lo que he aprendido hasta ahora y lo he estado usando como regla general: si está usando clases y métodos que esperan tipos genéricos, use interfaces como los tipos esperados. Y asegúrese de que el padre o la clase base use esa interfaz. De esa manera, puede usar todas las subclases en la medida en que implementan la interfaz.

Aquí la demo extendida


Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación. - De la crítica
aronisstav

1
@aronisstav Solo publiqué una demostración extendida de lo que encontré una buena respuesta que ya me ayudó. Pero tal vez a alguien más le resulte útil el trabajo que hice para ampliar la demostración. Eso es todo. Los comentarios no están destinados a poner un bloque de código, por eso lo encuentro más comprensible en una publicación de respuesta. Entonces, ¿cuál es el problema con eso?
zep

Su respuesta se marcó (¿automáticamente?) Debido a la longitud y el contenido, apareció en mi cola de revisión y le di mérito a las razones presentadas en la bandera. Su principal contribución (explicando que extendiste la demostración) sería mejor como comentario. Con el párrafo agregado quizás sea más útil.
aronisstav

@andzep su ejemplo de demostración extendido es realmente útil.
Namit

3
  1. La interfaz extiende la interfaz con la forma
  2. La interfaz extiende la clase con la forma
  3. La interfaz de implementación de clase debe implementar todos los campos proporcionados por la interfaz
  4. Clase implementa clase con forma
  5. La clase extiende la clase con todos los campos.

extendscentrarse en heredar y implementscentrarse en la restricción, ya sean interfaces o clases.


0

Extiende los implementos VS

  • extends: La clase secundaria (que se extiende) heredará todas las propiedades y métodos de la clase se extiende
  • implements: La clase que usa la implementspalabra clave deberá implementar todas las propiedades y métodos de la clase queimplements

Para decirlo en términos más simples:

  • extends: Aquí obtiene todos estos métodos / propiedades de la clase principal para que no tenga que implementar esto usted mismo
  • implements: Aquí hay un contrato que la clase debe cumplir. La clase tiene que implementar al menos los siguientes métodos / propiedades

Ejemplo:

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)

En el ejemplo podemos observar que la clase hija hereda todo de Person mientras que la clase man tiene que implementar todo de Person.

Si elimináramos algo de la clase man, por ejemplo, el método walk, obtendríamos el siguiente error de tiempo de compilación :

La clase 'man' implementa incorrectamente la clase 'Person'. ¿Querías extender 'Persona' y heredar sus miembros como una subclase? Falta la propiedad 'caminar' en el tipo 'hombre' pero es obligatoria en el tipo 'Persona'. (2720)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.