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
- La interfaz extiende la interfaz con forma
- La interfaz extiende la clase con forma
- La clase implementa la interfaz debe implementar todos los campos proporcionados por la interfaz
- La clase implementa clase con forma
- 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