interfaz clases typescript extends implements

clases - ¿Cuál es la diferencia entre ''extiende'' e ''implementos'' en TypeScript?



interface typescript (4)

Me gustaría saber qué tienen en común el hombre y el niño y en qué se diferencian.

class Person { name: string; age: number; } class child extends Person {} class man implements Person {}


Version corta

  • extends significa:

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

  • implements significa:

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

Más ...

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

extends al beneficio 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 basadas en clases existentes ...

implements serán más para el polimorfismo (ver wiki ). Pequeña cita:

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

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

class Man extends Human ...

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

class Man extends Human implements Person ...

.. entonces podemos usarlo en cualquier lugar, donde se requiera la Person . Solo tenemos que cumplir con la "interface" Personas (es decir, implementar todas sus cosas públicas) .

implement otra clase? Eso es realmente genial

La buena cara de Javascript (uno de los beneficios) es el soporte incorporado para escribir 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 ... tendrían 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 Typecript con más soporte tipeado. Y ahí es donde

class implements class

tiene su papel, donde tiene sentido

En lenguajes OOP como C# ... no hay forma de hacerlo ...

También la documentación debería ayudar aquí:

Clases de extensión de interfaces

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 la misma.

Esto es útil cuando tiene una gran jerarquía de herencia, 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 { select() { } } class TextBox extends Control { select() { } } class Image extends Control { } class Location { select() { } }

Entonces, mientras

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

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

extends foco en la herencia e implements foco en la restricción, ya sean interfaces o clases.


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étodos que tiene este tipo.
Por ejemplo:

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

Las instancias que implementan esta interfaz de Point deben tener dos miembros de número de tipo: x e y , y una distance método que recibe otra instancia de Point 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 clase Person 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 ''Persona''.
Falta la propiedad ''nombre'' en el tipo ''Hombre''.

Y eso es porque las interfaces carecen de implementación.
Entonces, si implement una clase, entonces solo toma su "contrato" sin la implementación, por lo que deberá 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 extend otra clase y no implement .


Gran respuesta de @ nitzan-tomer! Me ayudó mucho ... Extendí un poco su demo con:

IPoint interface; Point implements IPoint; Point3D extends Point;

Y cómo se comportan en funciones que esperan un tipo de IPoint.

Entonces, lo que he aprendido hasta ahora y 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 usen esa interfaz. De esa manera, puede usar todas las subclases en las que implementen la interfaz.

Hier la demo extendida