Orientación a objetos
La programación orientada a objetos en TypeScript es igual que la POO en JavaScript, salvo algunos añadidos, basados sobre todo en las posibilidades de tipado del lenguaje, que lo ponen a la altura de lenguajes como Java o C#. A continuación vamos a ver las diferencias respecto a JavaScript.
Tipado de atributos y métodos
La primera diferencia es que TypeScript obliga a declarar los atributos de la clase fuera del constructor. De esta forma tipamos dichos atributos. Opcionalmente se le puede poner un valor por defecto.
Ámbito público y privado
En TypeScript existen los modificadores de ámbito private y public. Sin embargo, desde hace poco tiempo, también se ha introducido en JavaScript el prefijo '#' para indicar que un atributo o método es privado (el resto es público). ¿Cuál es mejor usar en TypeScript?.
private vs #
Aunque usar private es perfectamente válido para que te avise de "casi" todos los errores que tengan que ver con acceder directamente a atributos (o métodos) privados desde fuera de la clase, tiene un problema. A la hora de compilar a JavaScript esos modificadores se eliminan (no existen en JavaScript), por lo que va a funcionar como si fueran públicas.
Usando el modificador '#' de JavaScript, estos atributos siguen siendo privados después de compilar a JavaScript, por lo que un acceso ilegal producirá error. De esta manera, sería recomendable usar este modificador si queremos que algo sea privado de verdad. Hasta hace poco, usar private era la única opción existente.
public y private en parámetros del constructor
TypeScript también permite pasarle al constructor parámetros con el modificador public o private. En este caso no hay que declarar esos atributos fuera del constructor y TypeScript asigna el valor del parámetro al atributo automáticamente. Estos 2 ejemplos a continuación son equivalentes:
Lo malo de esto es que si tenemos atributos que queramos que sean privados, no podemos usar el modificador de JavaScript '#' de esta manera, perdiendo sus ventajas. En su lugar utilizaremos el modificador private.
Interfaces
En TypeScript, las interfaces tienen 2 usos principales. El primero es el clásico de otros lenguajes de programación, obligar a la clase que implementa dicha interfaz a implementar ciertos métodos, o incluso ciertos atributos. El segundo sería para tipar objetos (JSON o instancias de clases) y establecer qué atributos deben tener.
Implementar interfaces en clases
Al igual que ocurre con otros lenguajes como Java o C#, podemos crear interfaces donde definimos métodos sin implementar, solo tipados. De esta manera, las clases que implementen una interfaz, están obligadas a implementar dichos métodos. También se pueden definir atributos que la clase que implementa la interfaz también deberá tener.
Interfaces para tipar objetos
En TypeScript se suelen utilizar mucho interfaces que solo contienen atributos para tipar variables, arrays, etc. Si tipamos usando una interfaz quiere decir, que el valor debe ser un objeto que tenga dichos atributos. Puede ser un objeto JSON con las mismas propiedades, o un objeto instanciado a partir de una clase que también tenga esas propiedades (o que implemente la interfaz).
Polimorfismo
En los lenguajes con orientación a objetos estáticamente tipados existe el concepto de Polimorfismo, y está ligado a la herencia. Este implica que a la hora de establecer el tipo para un objeto, se puede utilizar una clase base o una interfaz que implemente la clase del objeto. En definitiva, un tipo más genérico que contenga algunos de los atributos o métodos del objeto.
La limitación de usar polimorfismo es la de no poder acceder a atributos o métodos del objeto que no estén definidos en el tipo usado. Para poder acceder a ellos, debemos usar primero un casting (conversión) de tipos explícito.