다크 모드
Chapter 00. 시작하기 전에: jQuery 개발자를 위한 모던 Angular 22 준비운동
"Angular는 여전히 무겁고 어렵다는 과거의 편견을 버리자. 복잡했던 NgModule은 사라졌고, 컴포넌트는 단 한 줄로 독립 실행되며, 신호(Signals) 기반의 초고속 미세 반응형 엔진으로 무장한 2026 최신 Angular 22와 TypeScript 6.0의 핵심 멘탈 모델을 장착하자."
📋 이 장에서 처음 만나는 개념 — 앞으로 실습하며 막힐 때마다 돌아와 찾아보는 사전입니다.
| 개념 | 한 줄 요약 | 설명 위치 |
|---|---|---|
| Standalone Component | NgModule 등록 없이 컴포넌트 단독으로 필요한 의존성을 imports에 선언해 즉시 실행하는 표준 아키텍처 | 0.3.1 |
Angular Signals & httpResource | signal(), computed(), effect() 미세 반응형 상태와 신호 기반 선언적 비동기 HTTP 리소스 | 0.3.2 |
내장 Control Flow (@if, @for) & ... | 지시어 import 없이 템플릿에서 바로 쓰는 제어문과 Angular 22 템플릿 스프레드 연산자 | 0.3.3 |
OnPush 기본화 & Signal Forms | Zone.js 없이 변경된 신호만 정밀 갱신하는 전략 기본화 및 타입 안전한 Signal 기반 폼 정식화 | 0.3.4 |
| ES6+ & TypeScript 6.0 필수 문법 | const/let, 화살표 함수, 구조 분해, interface, 제네릭 <T>, 유니온 타입 | | 0.4 ~ 0.5 |
HttpClient & inject() | $.ajax를 대체하는 Angular 표준 HTTP 클라이언트와 생성자 없는 함수형 의존성 주입 | 0.6 ~ 0.7 |
TIP
🏁 이 장의 시작 파일
이 장은 본격적인 코딩에 앞서 개발 도구와 Angular 22 + TypeScript 6.0의 핵심 문법 지도를 익히는 준비운동 장입니다. 아직 프로젝트 파일을 수정하지 않으며, 0.9절의 간단한 플레이그라운드 미션으로 워밍업만 수행합니다. 이 장에서 손대는 파일: 없음 (사전처럼 언제든 돌아와 참고하십시오)
0.1 이 책을 읽는 방법과 대상 독자
이 책은 jQuery나 JSP 기반의 전통적 웹 개발 경험이 있는 사내 엔터프라이즈 개발자, 혹은 과거 Angular(v2~v15)나 다른 프레임워크를 찍먹해 보았지만 최신 아키텍처가 낯선 개발자가 전 세계 대기업과 금융권에서 가장 신뢰하는 Angular 22 + TypeScript 6.0을 손으로 직접 타이핑하며 체득하도록 설계된 실무 아키텍처 교재입니다.
처음 보는 문법이 나왔을 때 당황하지 않도록 매 장마다 다음 네 가지 장치를 둡니다.
| 장치 | 모양 | 의미 |
|---|---|---|
| 장 첫머리 "처음 만나는 개념" 표 | 📋 표 | 그 장에서 처음 등장하는 문법·도구 목록과 어디서 설명하는지(바로 아래 / 0장 / 뒤 장) 안내 |
| 🆕 처음 보는 문법 박스 | ::: info 박스 | 코드에 처음 등장한 문법을 초보자 눈높이에서 한 줄씩 풀이 |
| 🔬 심화 토글 박스 | ::: details 접기 | 내부 동작 원리나 실무 엣지 케이스를 다루며, 첫 독서 시 건너뛰어도 무방함 |
| 💪 직접 해보기 실습 미션 | 장 말미 미션 + 정답 토글 | 배운 개념을 내 손으로 직접 변주해 보고 정답 코드와 즉시 대조하는 훈련 |
- 과거 Angular 2 시절의 복잡한 NgModule은 잊으십시오: 최신 Angular 22에서는 별도의 모듈 파일(
app.module.ts) 없이 컴포넌트 하나가 독립적으로 작동하는 Standalone Component가 완벽한 기본값(standalone: true조차 생략 가능)입니다. - 구식 무거운 Change Detection(Zone.js)의 종말: 2024~2026년에 걸쳐 완성된 Angular Signals (
signal,computed,effect,linkedSignal,httpResource) 체계로, 가상 DOM(Virtual DOM) 비교 비용조차 없이 필요한 실제 DOM 노드만 핀포인트로 갱신합니다.
0.2 개발 도구 지도: <script src>에서 ng CLI와 Vite/esbuild로
jQuery 시절에는 HTML에 <script src="jquery.min.js"> 한 줄을 넣으면 끝이었습니다. 모던 Angular 22 프론트엔드는 다음 도구들이 역할을 분담합니다.
| 도구 / 용어 | 한 줄 설명 | jQuery 시절에 비유하면 |
|---|---|---|
| Node.js | 브라우저 밖(내 PC, 빌드 서버)에서 자바스크립트/타입스크립트를 실행하는 런타임 | – (개발 도구들을 돌리는 엔진) |
| npm | 패키지 설치·관리 도구. npm install로 package.json에 적힌 라이브러리를 node_modules/에 내려받음 | jQuery .js 파일을 직접 다운로드해 webapp/js/에 넣던 일 |
package.json | 프로젝트가 쓰는 라이브러리 버전과 실행 스크립트(scripts)를 적은 설정 파일 | Spring Maven의 pom.xml 또는 Gradle의 build.gradle |
Angular CLI (ng) | 프로젝트 생성, 개발 서버 기동(ng serve), 빌드, 테스트, 코드 생성을 담당하는 공식 CLI | – (프레임워크 표준 자동화 도구) |
| esbuild / Vite | Angular 17+부터 도입되어 Angular 22에서 완전히 성숙한 초고속 빌드·번들링 파이프라인 | JS 압축 도구(UglifyJS)를 수동으로 돌리던 일 |
| HMR (Hot Module Replacement) | 코드를 저장하면 브라우저 새로고침 없이 바뀐 컴포넌트 스타일/템플릿만 즉시 반영 | 코드 고칠 때마다 F5를 연타하던 일 |
| Angular DevTools | 브라우저 F12 개발자 도구에서 컴포넌트 트리와 Signals 의존성 그래프를 실시간 시각화 | console.log를 수십 줄 찍어 보던 일 |
실습 전에 설치할 개발 도구 2가지 (꼭 설치하십시오)
| 도구 | 설치 위치 | 왜 필요한가 |
|---|---|---|
Angular Language Service (Angular.ng-template) | VS Code 확장(Extensions) 마켓플레이스 | .html 템플릿과 인라인 템플릿 안에서 signal() 자동완성, 컴포넌트 태그 추적, 컴파일 타임 타입 오류 빨간 줄을 즉시 보여 줍니다. |
| Angular DevTools | Chrome / Edge 웹 스토어 | 브라우저 개발자 도구(F12)에 Angular 탭이 생깁니다. 각 컴포넌트의 signal/computed 값이 실시간으로 변하는 모습과 의존성 그래프를 눈으로 확인할 수 있습니다. |
SPA(Single Page Application)와 개발 서버 프록시(Proxy)
jQuery/JSP 게시판은 페이지를 이동할 때마다 서버가 새 HTML 전체를 내려주었습니다(MPA). 반면 SPA는 index.html 단 한 장만 내려받은 뒤, 화면 전환과 테이블 갱신은 Angular가 브라우저 메모리에서 DOM 부품만 갈아 끼워 처리합니다.
🍽️ 비유: 뷔페 접시(SPA) vs 식당 문 밖으로 쫓겨나기(전통 웹)
과거 JSP/jQuery 방식은 김치찌개 먹다가 계란말이 하나 추가 주문(list.do?page=2)했을 때, 식당 문 밖으로 쫓겨났다가 다시 들어와서 숟가락부터 식판까지 처음부터 다시 세팅받는 꼴이었습니다(화면 전체 깜빡임 + 모든 자바스크립트 변수 증발!). 반면 SPA는 뷔페 접시(index.html) 하나를 들고 다니면서, 빈 반찬 칸만 집게로 쏙쏙 바꿔 담는 것과 같습니다. 접시는 그대로 있고 음식(DOM 조각)만 바뀝니다.
또한 브라우저는 보안상 포트가 다른 서버(localhost:4200 프론트엔드 → localhost:8080 Spring Boot 백엔드)로 보낸 AJAX 응답을 차단합니다(CORS 정책). 이를 우회하기 위해 실습 환경의 proxy.conf.json(또는 Vite 프록시 설정)이 /api로 시작하는 모든 요청을 http://localhost:8080으로 안전하게 중계해 줍니다.
0.3 모던 Angular 22의 4대 패러다임 혁신
2026년 현재의 Angular 22는 과거 버전과 비교할 수 없을 만큼 간결하고 강력한 4대 표준 패러다임 위에 서 있습니다.
1) Standalone 기본화: NgModule의 완전한 퇴장
과거 Angular는 컴포넌트 하나를 만들면 반드시 app.module.ts의 declarations 배열에 등록해야만 했습니다.
Angular 19부터 standalone: true가 기본값이 되었고, Angular 22에서는 standalone: true 옵션조차 적을 필요 없이 모든 컴포넌트가 기본적으로 독립 실행됩니다(이 책에서는 명시적 학습을 위해 초반부에 표기하거나 생략 두 방식을 모두 안내합니다).
typescript
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-board',
// standalone: true 가 기본값이므로 생략 가능!
imports: [FormsModule], // 컴포넌트가 직접 필요한 도구만 선언!
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<h2>사내 기술 Q&A 게시판</h2>`
})
export class BoardComponent {}🏛️ 비유: 대형 관공서의 복잡한 결재 라인(NgModule) vs 무인 민원 발급기(Standalone)
- 과거 Angular (NgModule): 주민등록등본 한 장 떼려고 1층 총무과, 2층 관리과, 3층 기획과 도장을 다 받아야 했습니다. 컴포넌트 하나 만들 때마다 중앙 모듈 파일을 찾아가서 이름을 등록해야 했죠.
- 모던 Angular 22 (Standalone): 주민센터 로비에 놓인 **무인 민원 발급기(Standalone 컴포넌트)**입니다. 필요한 모듈만 자기
imports에 꽂으면 그 자리에서 즉시 독립 실행됩니다!
2) Signals & httpResource: 미세 반응형의 완성
상태를 선언할 때는 signal()을 쓰고, 파생 계산값은 computed(), 부수 효과는 effect()를 사용합니다. 나아가 Angular 22에서는 RxJS Observable을 수동 구독하지 않고도 검색어나 페이지 신호가 바뀔 때마다 자동으로 서버 데이터를 다시 가져오는 **httpResource()**가 실무 표준으로 자리 잡았습니다.
typescript
import { Component, signal, computed } from '@angular/core';
import { httpResource } from '@angular/common/http';
export class PostListComponent {
// 1. 반응형 신호(Signal) 선언
page = signal(1);
keyword = signal('');
// 2. 파생 신호(Computed): page나 keyword가 바뀔 때만 재계산
queryUrl = computed(() => `/api/posts?page=${this.page()}&keyword=${this.keyword()}`);
// 3. Angular 22 httpResource: queryUrl() 신호가 바뀌면 자동으로 HTTP GET 재요청!
postsResource = httpResource<Post[]>(() => this.queryUrl(), { defaultValue: [] });
}3) 내장 Control Flow (@if, @for, @let)와 템플릿 스프레드 연산자 (...)
더 이상 *ngIf, *ngFor를 쓰기 위해 CommonModule을 import하지 않습니다. 템플릿 엔진에 내장된 @if, @for ... track, @empty, @let 블록과 더불어, Angular 22에서 정식 지원되는 템플릿 내 스프레드 연산자(...) 및 객체/배열 리터럴 확장을 그대로 사용합니다.
html
@let total = posts().length;
@if (isLoading()) {
<div class="spinner">로딩 중...</div>
} @else {
<p>총 {{ total }}건의 게시글</p>
<table>
<tbody>
@for (post of posts(); track post.id; let idx = $index) {
<tr (click)="selectPreview({ ...post, viewedAt: '방금 전' })">
<td>{{ idx + 1 }}</td>
<td>{{ post.title }}</td>
</tr>
} @empty {
<tr>
<td colspan="2">등록된 게시글이 없습니다.</td>
</tr>
}
</tbody>
</table>
}4) ChangeDetectionStrategy.OnPush 기본화 및 Signal Forms 정식화
Angular 22 CLI로 생성되는 모던 컴포넌트는 Zone.js에 의존하지 않는 Zoneless + OnPush 변경 감지를 기본 전제로 삼습니다. 또한 기존의 무거운 ReactiveFormsModule(FormGroup, FormControl)과 단순한 FormsModule(ngModel)의 장점을 결합해, 스키마 기반 검증과 완벽한 타입 추론을 제공하는 Signal Forms 및 model() 양방향 시그널 바인딩이 정식화되었습니다(1.5장 및 5장에서 상세 실습).
🆕 처음 보는 문법: 이중 중괄호 {{ expr }} 보간법(Interpolation)과 신호 호출
Angular 템플릿에서 컴포넌트의 신호 값을 화면 텍스트로 출력할 때는 {{ post.title }} 또는 신호 함수 호출인 {{ totalCount() }}처럼 이중 중괄호를 사용합니다.
- 중요:
totalCount가signal(7)로 선언되었다면, 템플릿 안에서 반드시 괄호를 붙여{{ totalCount() }}형태로 호출해야 Angular가 "이 HTML 텍스트 노드가totalCount신호를 구독한다"고 기록합니다! 괄호를 빼먹으면 함수 본문 문자열이 출력되거나 타입 에러가 발생합니다.
0.4 jQuery 시절 자바스크립트(ES5) → 모던 자바스크립트(ES6+)
jQuery 코드는 보통 var와 function, 콜백으로 작성되었습니다. 이 책의 모든 코드는 모던 ES6+ 및 TypeScript 6.0 문법을 사용합니다.
1) 변수 선언: var → const / let
typescript
var count = 0; // ES5: 함수 스코프, 중복 선언 허용 → 버그의 온상
const MAX_SIZE = 20; // ES6: 재할당 불가능한 상수 (실무 코드의 95% 이상)
let currentPage = 1; // ES6: 재할당이 필요한 변수 (블록 { } 스코프)
currentPage = 2; // OK2) 화살표 함수(=>)와 깨지지 않는 this
typescript
// ES5 jQuery: 콜백 안에서 this가 바뀌어 var self = this 편법을 썼음
var self = this;
$('#btn').on('click', function () { self.loadPosts(); });
// ES6+ & Angular: 화살표 함수는 바깥 클래스 인스턴스의 this를 그대로 유지함!
this.http.get('/api/posts').subscribe((data) => {
this.posts.set(data); // this는 언제나 컴포넌트 인스턴스!
});3) 템플릿 리터럴, 구조 분해 할당, 스프레드 연산자(...)
typescript
const id = 3;
const url = `/api/posts/${id}/comments`; // 백틱(`) 안에 ${ }로 변수 삽입
const post = { id: 1, title: '공지', author: '김개발', likeCount: 0 };
const { title, author } = post; // 객체에서 필요한 속성만 꺼내기 (구조 분해)
// 불변성(Immutability) 업데이트: 기존 객체를 복사하고 일부 속성만 변경한 새 객체 생성
const updatedPost = { ...post, likeCount: post.likeCount + 1 };
const updatedList = [updatedPost, ... existingPosts];WARNING
Angular Signals에서는 왜 ...(스프레드 연산자)를 자주 쓸까요?posts.update(prev => [newPost, ...prev])처럼 배열이나 객체의 참조(Reference)를 새로 만들어 교체해야만, Angular의 Object.is 변경 감지기가 "값이 바뀌었구나!"라고 즉시 알아채고 화면을 갱신하기 때문입니다(3장에서 집중 해부).
4) 옵셔널 체이닝(?.)과 널 병합 연산자(??)
typescript
const length = post.children?.length ?? 0;
// post.children이 null이나 undefined면 에러를 내는 대신 undefined를 반환하고,
// ?? 연산자가 이를 받아 안전하게 기본값 0으로 대체합니다.0.5 TypeScript 6.0 핵심 문법: "자바스크립트 + 엄격한 타입 계약"
TypeScript는 브라우저에서 실행되기 전 컴파일 단계에서 오타와 타입 불일치를 잡아내는 정적 타입 언어입니다. Spring Boot 백엔드의 Java 컴파일러가 프론트엔드에 그대로 들어왔다고 생각하면 정확합니다.
1) 타입 어노테이션과 interface (백엔드 DTO와의 계약)
typescript
export interface Post {
id: number;
title: string;
author: string;
content: string;
category: 'DEV' | 'NOTICE' | 'FREE'; // 유니온 리터럴 타입: 이 3개 문자열만 허용!
createdAt: string;
children?: Post[]; // ?: 있어도 되고 없어도 되는 선택적(Optional) 속성
}2) 제네릭(Generics) <T>: "상자 안에 무엇이 담기는지 알려주기"
Java의 List<Post>와 똑같습니다. signal이나 HttpClient를 호출할 때 꺾쇠(< >) 안에 데이터 타입을 적어주면 에디터가 완벽한 자동완성을 제공합니다.
typescript
// Post 배열을 담는 반응형 신호 상자 (초기값은 빈 배열 [])
posts = signal<Post[]>([]);
// 서버 응답 본문이 { items: Post[]; total: number } 모양이라고 타입 지정
this.http.get<{ items: Post[]; total: number }>('/api/posts');3) 본 교재에서 자주 만나는 TypeScript 표기 사전
| 문법 | 의미 | 처음 나오는 곳 |
|---|---|---|
value as HTMLInputElement | 타입 단언(Type Assertion): 개발자가 타입을 보증함 | 1.5장, 3장 |
unknown | 정체를 알 수 없는 안전한 최상위 타입 (typeof 등으로 확인 후 사용) | 5장, 7장 |
Record<string, string> | 키가 문자열이고 값도 문자열인 사전(Map) 형태의 객체 타입 | 4장, 5장 |
keyof Post | Post 인터페이스의 속성 이름들만 모은 유니온 타입 ('id' | 'title' | ...) | 3장, 8장 |
private readonly http = inject(HttpClient) | 클래스 외부 접근을 막고(private) 재할당을 금지(readonly)하는 필드 선언 | 1장 ~ 전체 |
🔬 심화(건너뛰어도 됨): TypeScript 타입은 런타임(브라우저 실행 시점)에 모두 증발합니다
this.http.get<Post[]>('/api/posts')라고 적었다고 해서, 백엔드 서버가 실수로 이상한 JSON 객체를 내려보냈을 때 TypeScript가 런타임 에러를 막아주지는 못합니다. 빌드 과정에서 모든 : Post, <Post[]> 표시는 지워지고 순수 자바스크립트만 남기 때문입니다. 런타임 방어 코딩과 타입 가드(Type Guard)는 7장에서 깊이 있게 다룹니다.
0.6 $.ajax에서 Angular HttpClient와 httpResource로
jQuery의 $.ajax를 대신해 Angular는 @angular/common/http 패키지의 HttpClient(명령형/RxJS 기반)와 httpResource(선언형 Signal 기반)를 제공합니다.
| 하고 싶은 일 | jQuery ($.ajax) | Angular 22 (HttpClient) |
|---|---|---|
| 목록 조회 (GET) | $.get('/api/posts', { size: 20 }, cb) | this.http.get<PageRes>('/api/posts', { params: { size: 20 } }) |
| 게시글 등록 (POST) | $.ajax({ url, method: 'POST', data: JSON.stringify(body) }) | this.http.post<Post>('/api/posts', body) (JSON 직렬화 자동!) |
| 게시글 삭제 (DELETE) | $.ajax({ url: '/api/posts/' + id, method: 'DELETE' }) | this.http.delete<void>(`/api/posts/${id}`) |
| 공통 인증 헤더/에러 | $.ajaxSetup({ beforeSend: ... }) | 함수형 HttpInterceptorFn (withInterceptors, 12장) |
typescript
// HttpClient의 기본 구독 패턴 (1장부터 사용)
this.http.get<{ items: Post[] }>('/api/posts').subscribe({
next: (res) => {
this.posts.set(res.items); // = $.ajax의 success 콜백
},
error: (err) => {
alert('로딩 실패'); // = $.ajax의 error 콜백
}
});0.7 모던 Angular 22 아키텍처 핵심 지도
이 책을 끝까지 완주하며 우리 사내 게시판에 하나씩 장착할 기술 지도입니다.
| 개념 | 한 줄 설명 | 처음 쓰는 곳 | 심화 설명 |
|---|---|---|---|
signal(초기값) | .set()과 .update()로 값을 바꾸면 템플릿이 자동 갱신되는 반응형 상자 | 1장 Step 1 | 2장, 2.5장 |
@if, @for ... track, @empty | 조건 분기와 리스트 반복 렌더링을 담당하는 내장 제어문 | 1장 Step 2 | 1.5장 |
viewChild() & afterNextRender | 템플릿의 실제 DOM 요소를 Signal로 안전하게 참조하고 렌더링 직후 제어 | 1.5장 1.5.1 | 1.5장 |
input(), output(), model() | 부모↔자식 컴포넌트 간 함수형 단방향/양방향 Signal 입출력 | 1.5장 1.5.2 | 4장, 8장 |
computed() & effect() | 캐싱되는 파생 신호 계산기와 부수 효과 실행기 | 2장 2.3 | 2.5장, 3장 |
untracked() | effect 내부에서 특정 신호를 읽되 의존성 추적에서는 제외 | 3장 3.3 | 3장 |
Router & ActivatedRoute | SPA URL 이동 및 쿼리 파라미터(?page=2&keyword=ng) 반응형 동기화 | 4.5장 | 5장, 11장 |
@Injectable() Service & inject() | 컴포넌트에서 비즈니스 상태와 알고리즘을 분리하는 서비스와 함수형 DI | 5장 | 6장, 9장 |
계층적 DI (providers: [...]) | 전역 싱글톤이 아닌 특정 컴포넌트 서브트리에만 서비스를 격리 제공 | 5장, 6장 | 6장, 9장 |
0.8 사고방식 전환: "DOM을 찾아서 고친다" → "신호(Signal)를 바꾸면 화면이 따라온다"
| 상황 | jQuery 방식 (명령형: 어떻게 바꿀지 지시) | Angular 22 방식 (선언형: 상태만 변경) |
|---|---|---|
| 목록 그리기 | $('#tbody').empty().append(html문자열) | posts = signal<Post[]>([]) + @for (post of posts(); track post.id) |
| 입력값 읽기 | $('#title').val() | model() / Signal Forms / [ngModel]="title()" |
| 로딩 스피너 | $('#spinner').show() / .hide() | isLoading.set(true) + @if (isLoading()) |
| 행 삭제 | $(this).closest('tr').remove() | this.posts.update(list => list.filter(p => p.id !== id)) |
| 총 건수 갱신 | 삭제/등록할 때마다 $('#count').text(n) 수동 호출 | 템플릿에 {{ posts().length }} 한 번 적어두면 영구 자동 동기화 |
가장 중요한 첫 습관은 **"화면을 직접 건드리고 싶을 때마다, 대신 어떤 signal 값을 바꾸면 될지 생각하는 것"**입니다.
0.9 [직접 해보기] 실습 미션 💪
1장으로 넘어가기 전에, 손가락을 푸는 아주 짧은 TypeScript + Signals 워밍업 미션입니다. 눈으로만 보지 말고 빈 종이나 에디터에 직접 적어 보십시오.
📝 미션 요구사항
id(숫자),name(문자열),role('ADMIN' | 'USER')속성을 가진Member인터페이스를 선언하십시오.- 초기값으로
{ id: 1, name: '김코딩', role: 'USER' }객체 1개를 담은 배열 신호members = signal<Member[]>([...])를 선언하십시오. members신호 배열에서role === 'ADMIN'인 회원만 필터링하여 그 인원수를 반환하는 파생 신호adminCount = computed(...)를 작성하십시오.members.update(...)와 스프레드 연산자(...)를 사용하여{ id: 2, name: '박관리', role: 'ADMIN' }회원을 배열 맨 뒤에 불변(Immutable) 방식으로 추가하는 한 줄 코드를 작성하십시오.
💡 미션 정답 코드 확인하기
typescript
import { signal, computed } from '@angular/core';
// 1. 인터페이스와 리터럴 유니온 타입 정의
export interface Member {
id: number;
name: string;
role: 'ADMIN' | 'USER';
}
// 2. Member 배열을 담는 Signal 선언
const members = signal<Member[]>([
{ id: 1, name: '김코딩', role: 'USER' }
]);
// 3. 파생 신호(computed): members()가 바뀔 때만 관리자 수를 자동 재계산
const adminCount = computed(() => {
return members().filter(m => m.role === 'ADMIN').length;
});
console.log('초기 관리자 수:', adminCount()); // 0
// 4. 불변성을 유지하며 새 회원을 추가 (.update + 스프레드 연산자)
members.update(prev => [
...prev,
{ id: 2, name: '박관리', role: 'ADMIN' }
]);
console.log('추가 후 관리자 수:', adminCount()); // 1 (자동 갱신!)0.10 이번 장 핵심 요약 및 다음 단계 🚀
핵심 요약 3줄
- Angular 22는 복잡한
NgModule을 걷어낸 Standalone Component, Zone.js를 대체하는 Signals(signal,computed,effect,httpResource), 내장 **Control Flow(@if,@for)**를 기본 표준으로 사용합니다. - TypeScript 6.0의
interface와 제네릭(<T>)은 백엔드 DTO와 프론트엔드 상태를 엄격하게 묶어 주며, 실행 전에 에디터에서 오타와 버그를 잡아줍니다. - 화면(DOM)을 직접 찾아 수정하던 jQuery의 명령형 습관을 버리고, 신호(
signal)를 업데이트하면 화면이 저절로 따라오는 선언적 사고방식으로 전환해야 합니다.
다음 단계: 이제 준비운동이 끝났습니다! Chapter 01로 넘어가서 수년간 사내 인트라넷을 지탱해 온 jQuery 레거시 게시판(legacy-board.html)을 직접 실행해 3대 치명적 버그를 터뜨려 보고, 이를 Angular 22 Standalone 컴포넌트로 밑바닥부터 재구축해 봅시다!