Apariencia
📙 Clase 16 — Angular con TypeScript: crear y entender el proyecto
TypeScript · 2026-08-07 · Carpeta:
02-Ejercicios/Angular/proyectoAngular⬅️ Volver al índice de clases
🎯 Qué aprendí
- Por qué Angular y TypeScript son socios naturales: todo proyecto Angular usa TypeScript desde el primer comando, sin configurar nada extra.
- Cómo instalar el Angular CLI globalmente y verificarlo con
ng version. - El flujo completo:
ng new→cd→ng serve→http://localhost:4200/. - Qué es un decorador (
@Component) y cómo Angular usa standalone components hoy — sinAppModule, sindeclarations, cada componente declara sus propiosimports. - La cadena de
tsconfig.json→tsconfig.app.json+tsconfig.spec.json(el mismo patrón dereferencesque ya viste en las Clases 13 y 15). - 🔎 Un hallazgo real que contradice al material que estudié: el artículo dice que habilitar decoradores es "fundamental" — pero verifiqué que TypeScript 6.0 ya compila
@ComponentsinexperimentalDecorators, usando el nuevo estándar de decoradores de ECMAScript. Angular lo sigue incluyendo por costumbre/compatibilidad, no porque sea estrictamente obligatorio hoy. - 🔎 Otro hallazgo real, y en dirección opuesta a la Clase 15:
ng servesí revisa tipos en cada guardado (a diferencia denpm run devde Vite, que no revisaba nada). Lo comprobé metiendo un error de tipos a propósito. - 🐛 Un tercer incidente real: TypeScript 6.0 exige
rootDirexplícito en cuanto definesoutDir(antes lo inferia solo) — Angular CLI 22 generó lostsconfigsinrootDir, así que tronaban conerror TS5011. Lo diagnostiqué y arreglé agregando una sola línea a cada archivo.
📚 Definiciones clave
| Término | Qué es | Ejemplo de esta clase |
|---|---|---|
ng | Comando del Angular CLI — crea, sirve y compila proyectos Angular | ng new, ng serve, ng build |
@Component({...}) | Decorador que le dice a Angular cómo tratar una clase como componente visual | @Component({ selector: 'app-root', ... }) |
| Standalone component | Componente que declara sus propios imports, sin necesitar un NgModule | imports: [RouterOutlet] |
signal(...) | Primitiva reactiva de Angular — un valor que Angular sabe cuándo cambió | title = signal('proyectoAngular') |
📖 PARTE TEÓRICA
🤝 1. Por qué Angular y TypeScript son una combinación natural
Angular es uno de los frameworks más usados para construir interfaces — se destaca por manejar datos de forma eficiente y estructurada. TypeScript encaja perfecto porque su sistema de tipos permite validar esos datos antes de que lleguen a producción.
La ventaja concreta: todo proyecto Angular ya trae TypeScript integrado desde el día uno — no hay que instalar nada aparte ni tocar un tsconfig.json vacío como en otras clases. Eso trae:
- Mayor seguridad en el código (errores de tipo detectados en el editor, no en el navegador).
- Detección temprana de errores — antes de correr nada.
- Autocompletado más preciso, porque el editor conoce la forma exacta de tus datos.
🧪 Entrevista: ¿Por qué Angular usa TypeScript de forma nativa? Porque el propio framework está escrito en TypeScript y su CLI genera todos los archivos ya tipados — no es una capa opcional como en otros frameworks, es parte del diseño desde el origen.
🛠️ 2. Instalar el Angular CLI y verificarlo
bash
sudo npm install -g @angular/cli
ng versionVerificado en este equipo — ng version muestra el logo en ASCII y la versión instalada, tal como describe el material:
$ ng version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
Angular CLI : 22.1.3
Angular : 22.1.0
Node.js : 24.18.0💡 El número de versión que veas tú probablemente sea distinto — Angular saca versiones mayores cada pocos meses. Lo importante es que aparezca el logo ASCII sin errores: confirma que el CLI quedó bien instalado.
🆕 3. Crear el proyecto: ng new
bash
ng new proyecto-angularEl asistente pregunta, en orden:
- ¿Qué hojas de estilo quieres usar? (CSS, SCSS, Sass, Less) — en este proyecto real se eligió CSS (confirmado:
src/styles.cssysrc/app/app.css, sin ningún archivo.scss). - ¿Habilitar Server-Side Rendering (SSR)? — en este proyecto real se respondió No (confirmado: no existe ningún
server.tsni configuración de SSR enangular.json).
bash
cd proyecto-angular
ng serveVerificado en este equipo — el proyecto compila y queda escuchando en el puerto 4200:
$ ng serve
Application bundle generation complete. [0.814 seconds]
Watch mode enabled. Watching for file changes...
➜ Local: http://localhost:4200/💡 Detalle que no está en el material original: en el log aparece una línea que dice
[vite] (client) Re-optimizing dependencies— elng servemoderno usa Vite internamente para el servidor de desarrollo (desde Angular 17+). Es el mismo Vite que ya conoces de la Clase 15, solo que aquí Angular lo orquesta por ti, sin que tengas que tocar ningúnvite.config.ts.
Abrí http://localhost:4200/ en el navegador y confirmé la página de bienvenida de Angular, sin errores en consola.
🗂️ 4. Estructura real del proyecto — y un nombre que cambió
proyectoAngular/
├── public/
│ └── favicon.ico
├── src/
│ ├── app/
│ │ ├── app.ts ← lógica del componente (TypeScript)
│ │ ├── app.html ← plantilla del componente
│ │ ├── app.css
│ │ ├── app.config.ts ← configuración de la app (providers, router)
│ │ └── app.routes.ts ← definición de rutas
│ ├── index.html
│ ├── main.ts ← punto de entrada
│ └── styles.css
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.spec.json
└── angular.json⚠️ Esto cambió respecto al material original. El artículo habla de
app.component.tsyapp.component.html— ese era el nombre clásico de Angular. En la versión del CLI instalada hoy (22.1.3), el schematic por defecto generaapp.tsyapp.html, sin el infijo.component.. El concepto es idéntico (lógica en.ts, plantilla en.html); solo cambió la convención de nombres.
🎭 5. El decorador @Component y los standalone components
typescript
// src/app/app.ts
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.html',
styleUrl: './app.css'
})
export class App {
protected readonly title = signal('proyectoAngular');
}Un decorador es una función especial (marcada con @) que se coloca justo encima de una clase, propiedad o método, y le agrega metadatos o modifica su comportamiento sin cambiar el código de la clase en sí. @Component le dice a Angular: "esta clase no es una clase cualquiera, es un componente visual — así es como debes tratarla".
🧪 Entrevista: ¿Qué es un decorador en TypeScript/Angular? Una función que se antepone con
@a una clase, propiedad o método para agregarle metadatos o modificar su comportamiento en tiempo de compilación, sin tocar la lógica interna de la clase.
Fíjate en tres detalles reales de este componente, comparados con lo que describe el material:
| Propiedad del decorador | Lo que dice el material | Lo que hay en el proyecto real |
|---|---|---|
| Estilos | styleUrls: ['./app.component.css'] (plural, array) | styleUrl: './app.css' (singular, string) |
| Módulo | Se asume un AppModule con declarations: [AppComponent] | No existe AppModule — es un standalone component |
title | title = 'proyecto-angular'; (propiedad simple) | title = signal('proyectoAngular'); (signal reactiva) |
imports: [RouterOutlet] es la clave de los standalone components: en vez de registrar el componente en un NgModule central (declarations, imports, bootstrap), cada componente declara sus propios imports directamente en su decorador. main.ts arranca la app sin pasar por ningún módulo:
typescript
// src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));📝 Esto también es distinto del Angular "clásico" que describe el material —
bootstrapApplicationreemplaza al viejoplatformBrowserDynamic().bootstrapModule(AppModule). Es la forma estándar desde Angular 17+; ya no hace falta unAppModulepara una app simple como esta.
⚙️ 6. La cadena de tsconfig: mismo patrón que ya conoces
json
// tsconfig.json (fragmento real)
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "ES2022",
"module": "preserve"
},
"angularCompilerOptions": {
"strictInjectionParameters": true,
"strictInputAccessModifiers": true
},
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.spec.json" }
]
}Exactamente el mismo patrón de references que viste en la Clase 15 con Vite: tsconfig.json no compila nada por sí mismo, solo apunta a tsconfig.app.json (tu código de app, con outDir propio) y tsconfig.spec.json (los archivos de prueba, *.spec.ts).
💡
angularCompilerOptionses una sección aparte, exclusiva del compilador de Angular (@angular/compiler-cli) — no son opciones de TypeScript puro, son reglas extra que Angular revisa sobre tu código (por ejemplo,strictInputAccessModifiersevita que uses un@Input()privado de forma incorrecta desde una plantilla).
🐛 6.1. Un tercer incidente real: rootDir explícito obligatorio (TS 6.0)
Este es otro problema que apareció trabajando en el proyecto real, sin relación con Angular en sí — es un cambio de comportamiento de TypeScript 6.0.
Síntoma: tsc --build (o el propio ng build) marcaba error en la línea de outDir de tsconfig.app.json y tsconfig.spec.json.
Causa real: antes de TypeScript 6.0, si tenías outDir pero no rootDir, el compilador inferia automáticamente cuál era la carpeta raíz de tus fuentes. Desde TS 6.0 eso ya no pasa — si defines outDir, tienes que decir explícitamente rootDir también, o el compilador se niega a adivinar por ti:
$ tsc --build --force
tsconfig.app.json(6,5): error TS5011: The common source directory of 'tsconfig.app.json' is './src'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.
Visit https://aka.ms/ts6 for migration information.Angular CLI 22 genera sus tsconfig.app.json/tsconfig.spec.json sin rootDir — por eso el error aparece apenas actualizas a una versión de TypeScript que exige esta regla más estricta.
El fix, agregando una sola línea a cada archivo:
json
// tsconfig.app.json y tsconfig.spec.json
{
"compilerOptions": {
"outDir": "./out-tsc/app",
"rootDir": "./src",
"types": []
}
}Verificado: con rootDir presente, tsc --build --force termina con código de salida 0, sin ningún error.
💡
out-tsc/(la carpeta de salida que genera este build interno de TypeScript, separado deldist/deng build) ya viene incluida en el.gitignoreque trae el proyecto por defecto — no ensucia el repositorio aunque la generes varias veces.
🧪 Tip de entrevista: ¿qué relación hay entre
outDiryrootDiren TypeScript?rootDirle dice al compilador cuál es la carpeta que contiene TODOS tus archivos fuente —outDirreproduce esa misma estructura de carpetas, pero compilada, dentro de la carpeta de salida. SinrootDirexplícito, TypeScript tiene que adivinar esa carpeta común a partir de tusinclude; desde TS 6.0, ya no adivina — lo exige por escrito.
🔎 7. Hallazgo real: ¿son los decoradores realmente "fundamentales"?
El material dice: "Habilitación de decoradores, que son fundamentales para la comunicación entre Angular y TypeScript" — dando a entender que sin experimentalDecorators: true el proyecto no compilaría. Lo puse a prueba.
Quité la línea "experimentalDecorators": true de tsconfig.json, borré la caché (.angular/cache) para estar seguro, y corrí ng build de nuevo:
$ ng build
✔ Building...
Application bundle generation complete. [2.188 seconds] ← compiló IGUAL, sin la banderaCompiló sin problema. La razón, verificada por separado con tsc puro (fuera de Angular): TypeScript 6.0 ya soporta el nuevo estándar de decoradores de ECMAScript (stage 3, nativo desde TS 5.0) — no necesita ninguna bandera especial. experimentalDecorators solo activa el sistema antiguo, específico de TypeScript, que existía antes de que el estándar se aprobara. Comparé el JavaScript generado para el mismo decorador, con y sin la bandera:
javascript
// CON experimentalDecorators: true (sistema legacy)
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
// usa Reflect.decorate(...)
};
Saludo = __decorate([MiDecorador], Saludo);javascript
// SIN experimentalDecorators (estándar ECMAScript, TS 5.0+)
var __esDecorate = (this && this.__esDecorate) || function (...) {
// usa Symbol.metadata, __runInitializers(...)
};Son dos implementaciones de decoradores completamente distintas por dentro, generando código diferente — y ambas hacen que @Component compile.
⚠️ Esto no significa que debas borrar la línea de tu propio proyecto — Angular sigue incluyéndola por defecto, probablemente porque su sistema de inyección de dependencias (que usa metadatos de tipos en tiempo de ejecución) confía en el comportamiento específico del sistema legacy, no solo en que el componente compile. La lección real es otra: verificar antes de repetir una afirmación — "es fundamental" resultó ser más matizado de lo que decía el material.
🔎 8. Hallazgo real: ng serve SÍ revisa tipos (al revés que Vite)
En la Clase 15 verifiqué que npm run dev de Vite nunca revisa tipos — solo transpila. Con Angular probé exactamente lo mismo, y el resultado fue opuesto.
Con ng serve corriendo, agregué a propósito una línea con un tipo incorrecto en app.ts:
typescript
protected readonly numero: number = "esto no es un number";❯ Changes detected. Rebuilding...
Application bundle generation failed. [0.133 seconds]
✘ [ERROR] TS2322: Type 'string' is not assignable to type 'number'.
src/app/app.ts:12:21:El bundle falló de inmediato — a diferencia de Vite, que dejaba correr la app igual con el error de tipos adentro. Quité la línea y el servidor se recuperó solo ("Page reload sent to client(s)").
| Vite + React (Clase 15) | Angular CLI (esta clase) | |
|---|---|---|
¿dev/serve revisa tipos? | No — solo transpila | Sí — falla el build ante cualquier error |
| ¿Por qué? | Usa esbuild/SWC (solo quita tipos) | Usa @angular/compiler-cli, compilación AOT completa |
| ¿Cuándo lo descubres? | Recién en npm run build | Al instante, en cada guardado |
💡 Esto tiene una consecuencia práctica real: en Angular es mucho más difícil arrastrar un error de tipos sin darte cuenta — el propio servidor de desarrollo te lo muestra de inmediato, sin esperar a un build de producción.
✍️ 9. Editar la plantilla inicial
Cambiar el mensaje de bienvenida es tan simple como editar app.html:
html
<!-- antes -->
<h1>Hello, {{ title() }}</h1>
<!-- después -->
<h1>Hola, felicidades {{ title() }}</h1>📝 Fíjate en
title()— con llamada a función, notitlea secas. Comotitlees unasignal(sección 5), hay que "leerla" invocándola como función dentro de la plantilla — es la sintaxis que Angular usa para saber exactamente cuándo ese valor cambió y solo actualizar esa parte del DOM.
Verificado en Chrome real: guardé el cambio con ng serve corriendo, y el texto se actualizó sin recargar la página — el mismo concepto de HMR que ya viste en Vite (Clase 12, Clase 15), aquí bajo el nombre "Component update sent to client(s)" en el log de Angular.
🆕 10. Resumen: lo que cambió desde que se grabó el material original
| En el material original | Verificado en este equipo (Angular 22) |
|---|---|
app.component.ts / app.component.html | app.ts / app.html (sin el infijo .component.) |
styleUrls: [...] (plural, array) | styleUrl: '...' (singular, string) |
Se asume un AppModule | No existe — standalone components, bootstrapApplication |
title = 'proyecto-angular'; | title = signal('proyectoAngular'); (reactividad con signals) |
| "Los decoradores son fundamentales" (implica que la bandera es obligatoria) | Compila igual sin experimentalDecorators — TS 6.0 ya soporta decoradores estándar |
No menciona qué corre por dentro ng serve | Usa Vite internamente desde Angular 17+ |
No se menciona rootDir | TypeScript 6.0 lo exige explícito en cuanto hay outDir — sin él, error TS5011 |
💻 PARTE PRÁCTICA
Carpeta trabajada: 02-Ejercicios/Angular/proyectoAngular/ (creada con el CLI real, ng serve y ng build ya verificados arriba).
bash
ng version
cd 02-Ejercicios/Angular/proyectoAngular
npm start # equivale a "ng serve"Verificado en Chrome real, sirviendo el proyecto en http://localhost:4200/:
Hello, proyectoAngular
Congratulations! Your app is running. 🎉Build de producción verificado también:
$ npm run build
Application bundle generation complete. [2.564 seconds]
Output location: dist/proyectoAngularTodo verificado y corriendo. ✅
🏋️ EJERCICIOS CON SOLUCIÓN
Ejercicio 1 — Verificar la instalación con ng version
Corre ng version en tu terminal y confirma que aparece el logo ASCII y un número de versión, sin errores.
💡 ¿Sabías que…? — `ng version` también funciona DENTRO de un proyecto
Corrido dentro de la carpeta de un proyecto Angular, ng version muestra información extra: qué paquetes de @angular/* tiene instalados ese proyecto específico, además de la versión global del CLI.
Ver solución
bash
ng versionSalida esperada: el logo ASCII de Angular, seguido de una tabla con Angular CLI, Angular, Node.js, Package Manager y sus versiones.
Ejercicio 2 — Generar un segundo componente con el CLI
Usa ng generate component saludo (o ng g c saludo) dentro del proyecto. ¿Qué archivos crea, y qué nombre usan (con o sin .component.)?
💡 ¿Sabías que…? — el CLI genera Y registra el componente en un solo paso
ng generate component no solo crea los archivos — también actualiza automáticamente cualquier configuración necesaria para que el componente quede listo para usarse (en un proyecto standalone, simplemente queda disponible para importar).
Ver solución
bash
cd 02-Ejercicios/Angular/proyectoAngular
ng generate component saludoArchivos generados (con la convención moderna, sin .component.):
src/app/saludo/saludo.ts
src/app/saludo/saludo.html
src/app/saludo/saludo.css
src/app/saludo/saludo.spec.tsEjercicio 3 — Editar app.html y confirmar el HMR
Cambia el texto del <h1> en app.html (con ng serve corriendo) y confirma que el navegador se actualiza sin que tú recargues la página.
💡 ¿Sabías que…? — Angular llama a esto "Component update", no "HMR"
El concepto es el mismo que viste con Vite en la Clase 12 y Clase 15, pero el log de Angular lo describe distinto: "Component update sent to client(s)" en vez de "hmr update".
Ver solución
html
<!-- app.html -->
<h1>Hola, felicidades {{ title() }}</h1>Terminal esperada:
Component update sent to client(s).Ejercicio 4 — Cambiar el valor de una signal con un evento de clic
Agrega un <button> en app.html que, al hacer clic, cambie el valor de title usando title.set(...).
💡 ¿Sabías que…? — las signals tienen `.set()` y `.update()`
title.set('nuevo valor') reemplaza el valor completo. title.update(actual => actual + '!') lo calcula a partir del valor anterior — útil para contadores o acumuladores, parecido a la forma funcional de setCount que ya viste con useState en React (Clase 15).
Ver solución
typescript
// app.ts
protected cambiarTitulo(): void {
this.title.set('¡Cambiado desde un clic!');
}html
<!-- app.html -->
<button (click)="cambiarTitulo()">Cambiar título</button>Al hacer clic, el <h1> cambia sin recargar la página — la signal notifica a Angular exactamente qué parte del DOM actualizar.
Ejercicio 5 — Forzar un error de tipos con ng serve corriendo
Agrega protected readonly x: number = "texto"; en app.ts, con ng serve corriendo. Anticipa qué esperas ver, y compáralo con lo que pasaba en Vite (Clase 15).
💡 ¿Sabías que…? — Angular usa compilación AOT también en desarrollo
A diferencia de esbuild/SWC (que solo transpilan), el compilador de Angular (@angular/compiler-cli) hace Ahead-of-Time compilation real incluso en ng serve — por eso detecta errores de tipos al instante, no solo en producción.
Ver solución
typescript
protected readonly x: number = "texto";Terminal real — el bundle falla de inmediato:
Application bundle generation failed.
✘ [ERROR] TS2322: Type 'string' is not assignable to type 'number'.💡 En Vite/React, este mismo error NO detenía
npm run dev— solonpm run buildlo detectaba. Angular es más estricto desde el desarrollo mismo.
Ejercicio 6 — Leer la cadena de tsconfig del proyecto Angular
Abre tsconfig.app.json y compáralo con tsconfig.app.json de tu proyecto React de la Clase 15. ¿Qué tienen en común?
💡 ¿Sabías que…? — el patrón `references` no es exclusivo de un framework
Tanto Vite como Angular CLI adoptaron el mismo patrón de TypeScript: un tsconfig.json "orquestador" con references a configs específicas (app, node/spec). No es casualidad — es una característica de TypeScript que cualquier herramienta puede aprovechar, no algo inventado por React o Angular.
Ver solución
Ambos usan "files": [] + "references": [...] en el tsconfig.json raíz, y ambos tienen un outDir propio en su config de aplicación. La diferencia: Angular separa app de spec (pruebas), mientras Vite separaba app de node (el entorno de vite.config.ts) — cada framework divide según lo que necesita, pero el patrón de fondo es el mismo.
Ejercicio 7 — Probar sin experimentalDecorators en tu propio proyecto
Quita la línea "experimentalDecorators": true de tsconfig.json y corre ng build. Anticipa el resultado antes de probarlo.
💡 ¿Sabías que…? — verificar > memorizar lo que dice un tutorial
Este es exactamente el ejercicio que hice yo para escribir la sección 7 de la teoría. La lección no es "quita la bandera de tu proyecto real" (Angular la deja por una razón), sino aprender a comprobar afirmaciones en vez de repetirlas de memoria.
Ver solución
bash
rm -rf .angular/cache dist
ng buildCompila sin errores, exactamente igual que con la bandera presente — confirma que TypeScript 6.0 no depende de ella para procesar @Component.
⚠️ Restaura la línea después del ejercicio — no hay motivo para quitarla de tu proyecto real, solo era para comprobar la afirmación.
Ejercicio 8 — Comparar decoradores legacy vs estándar, aislado
Fuera de Angular, en un archivo demo.ts con un decorador simple de clase, compila una vez con tsc --experimentalDecorators demo.ts y otra vez con tsc demo.ts (sin la bandera). Compara el .js generado.
💡 ¿Sabías que…? — los helpers delatan qué sistema de decoradores se usó
Busca __decorate + Reflect.decorate (sistema legacy, con la bandera) contra __esDecorate + Symbol.metadata (estándar ECMAScript, sin la bandera) — son la huella dactilar de cada sistema en el JavaScript compilado.
Ver solución
typescript
// demo.ts
function MiDecorador(constructor: Function) {
console.log("Decorador aplicado a:", constructor.name);
}
@MiDecorador
class Saludo {
mensaje = "hola";
}Con --experimentalDecorators: el .js usa __decorate y Reflect.decorate. Sin la bandera: usa __esDecorate, __runInitializers y Symbol.metadata. Ambos producen un programa funcional — pero son implementaciones distintas por dentro.
Ejercicio 9 — Explorar el dist/ de producción
Corre ng build y revisa la carpeta dist/proyectoAngular/ generada.
💡 ¿Sabías que…? — Angular también genera archivos con hash, como Vite
Igual que viste en la Clase 15, los archivos de dist/ llevan un hash en el nombre (main-3RJTBKW5.js) para evitar que el navegador sirva una versión vieja desde caché.
Ver solución
bash
ng build
find dist/proyectoAngular -maxdepth 2Terminal esperada:
dist/proyectoAngular/browser/index.html
dist/proyectoAngular/browser/main-3RJTBKW5.js
dist/proyectoAngular/browser/styles-5INURTSO.cssEjercicio 10 — Integrador: un componente nuevo con signal y evento
Crea un componente contador (ng g c contador) con una signal inicializada en 0 y un botón que la incremente en 1 cada clic. Úsalo dentro de app.html.
💡 ¿Sabías que…? — este ejercicio junta TODO lo de la clase
ng generate para crear el componente, @Component con imports (standalone), signal + .update() para el estado reactivo, y un evento (click) en la plantilla — el mismo patrón que ya armaste con React y useState en la Clase 15, ahora con las herramientas propias de Angular.
Ver solución
bash
ng generate component contadortypescript
// src/app/contador/contador.ts
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-contador',
templateUrl: './contador.html',
styleUrl: './contador.css'
})
export class Contador {
protected readonly valor = signal(0);
incrementar(): void {
this.valor.update(actual => actual + 1);
}
}html
<!-- src/app/contador/contador.html -->
<p>Valor: {{ valor() }}</p>
<button (click)="incrementar()">+1</button>typescript
// app.ts — agregar el import
import { Contador } from './contador/contador';
@Component({
selector: 'app-root',
imports: [RouterOutlet, Contador],
templateUrl: './app.html',
styleUrl: './app.css'
})html
<!-- app.html — usarlo en cualquier parte -->
<app-contador></app-contador>Al hacer clic en el botón, el número sube sin recargar la página.
❓ Preguntas y respuestas (autoevaluación)
1. ¿Por qué Angular usa TypeScript de forma nativa, sin configuración extra?
Porque el propio framework está construido en TypeScript, y su CLI genera todos los archivos de un proyecto nuevo ya tipados desde el primer comando.
2. ¿Cuál es el comando para instalar el Angular CLI de forma global?
sudo npm install -g @angular/cli. Se verifica conng version.
3. ¿Qué comando crea un proyecto Angular nuevo, y qué preguntas hace?
ng new nombre-proyecto— pregunta qué hoja de estilos usar (CSS, SCSS…) y si quieres habilitar Server-Side Rendering.
4. ¿En qué puerto corre ng serve por defecto?
4200—http://localhost:4200/.
5. ¿Qué es un decorador, en una frase?
Una función que se antepone con
@a una clase (o propiedad/método) para agregarle metadatos o modificar su comportamiento, sin tocar su lógica interna.
6. ¿Por qué el proyecto real de esta clase no tiene ningún AppModule?
Porque usa standalone components — cada componente declara sus propios
importsdirectamente en@Component, ymain.tsarranca la app conbootstrapApplicationen vez de registrar un módulo central.
7. ¿ng serve revisa errores de tipos mientras desarrollas?
Sí — a diferencia de
npm run devde Vite (Clase 15), Angular usa compilación AOT real incluso en desarrollo, así que un error de tipos hace fallar el bundle de inmediato.
8. ¿Es experimentalDecorators: true estrictamente obligatorio para que @Component compile hoy?
No, verificado: TypeScript 6.0 soporta el nuevo estándar de decoradores de ECMAScript sin esa bandera. Angular la sigue incluyendo por defecto, pero quitarla no rompe la compilación básica.
9. ¿Qué diferencia hay entre title = 'texto' y title = signal('texto')?
La primera es una propiedad normal — Angular no sabe cuándo cambia sin revisar todo el componente. La segunda es una signal: un valor reactivo que Angular puede "escuchar" para saber exactamente qué actualizar en el DOM, sin revisar el resto.
10. En app.html, ¿por qué se escribe {{ title() }} y no {{ title }}?
Porque
titlees unasignal, no un valor plano — hay que "leerla" invocándola como función. Escribir{{ title }}mostraría la signal en sí (su representación interna), no el valor que contiene.
📎 Apuntes relacionados
- Clase 2: aserciones y
! - Clase 12: HMR y
<script> - Clase 13:
outDir,tsc -p, cadena detsconfig - Clase 15: Vite + React, comparación de
devvsbuild - Conceptos
- Comandos
➡️ Siguiente
Utility types — Partial, Pick, Omit, Record… transformar tipos existentes sin reescribirlos.