Use Cases (更新: 2026/6/2)

用 Claude Code 做 Angular 开发:CLI、Standalone、表单、HTTP 与测试实战

面向真实 Angular 项目,讲解如何用 Claude Code 处理 CLI、standalone component、Reactive Forms、HttpClient、单元测试与 E2E。

用 Claude Code 做 Angular 开发:CLI、Standalone、表单、HTTP 与测试实战

在 Angular 项目里使用 Claude Code,重点不是让它一次性“生成一个漂亮页面”。真正有价值的做法,是让它先读懂项目,再按 Angular CLI、standalone component、Reactive Forms、HttpClient、测试和代码审查的顺序推进。这样生成的差异更小,也更容易被团队 review。

standalone component 可以理解为“不依赖 NgModule 注册、自己声明 imports 的组件”。Reactive Forms 是“把表单值和校验规则放在 TypeScript 中显式管理”的方式。HttpClient 是 Angular 官方提供的后端通信 API。把这些词先讲清楚,给 Claude Code 的指令才不会停留在“帮我写个表单”。

参考资料建议固定使用官方文档:Angular CLIReactive formsHttpClientAngular testing 以及 Claude Code workflows。站内延伸可以看 TypeScript 技巧测试策略CLAUDE.md 最佳实践

先限定 Claude Code 的工作边界

给 Claude Code 一个 harness,也就是“代理工作的安全框架”。它应该知道能改哪些文件、不能改哪些文件、项目使用什么测试命令,以及 review 时要看哪些问题。

先阅读这个 Angular 项目。请查看 package.json、angular.json、src/app,
说明项目是否使用 standalone component、当前测试工具是什么、
HttpClient 在哪里提供、命名规范有哪些。现在不要编辑文件。
层级交给 Claude Code人来决定
Angular CLI生成命令、文件路径、依赖检查路由归属、团队命名规范
Componentimports、模板、signals、事件处理UI 文案、可访问性、发布风险
Reactive FormsFormGroup、校验、提交状态业务规则、错误提示语
Service / HTTP类型、API 方法、测试后端API 合约、认证、错误分类
测试单元和 E2E 用例覆盖率目标、是否合并
flowchart LR
  P[Prompt] --> C[Angular CLI]
  C --> A[Standalone component]
  A --> F[Reactive Forms]
  A --> S[Ticket service]
  S --> H[HttpClient]
  F --> U[Unit tests]
  A --> E[E2E tests]
  U --> R[Review]
  E --> R

用 Angular CLI 建立可验证的起点

新项目可以从 CLI 开始。老项目不要直接套命令,而是先让 Claude Code 读取配置。

npm install -g @angular/cli
ng new support-desk-angular --standalone --routing --style css
cd support-desk-angular
ng generate component features/tickets/ticket-intake --standalone
ng generate service data/ticket
ng test

这里的重点是“先确认基线”。如果 ng test 在修改前就失败,Claude Code 后面会把旧问题和新问题混在一起。多人协作时,还要明确“只处理这个功能目录,不回滚其他未提交修改”。

先写 typed service,再写 UI

表单之前先定义 API service,review 会更清楚。下面的文件可以放在 src/app/data/ticket.service.ts

import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { Observable } from 'rxjs';

export type TicketPriority = 'low' | 'medium' | 'high';

export interface TicketDraft {
  title: string;
  email: string;
  priority: TicketPriority;
  message: string;
}

export interface Ticket extends TicketDraft {
  id: string;
  createdAt: string;
}

@Injectable({ providedIn: 'root' })
export class TicketService {
  private readonly http = inject(HttpClient);
  private readonly baseUrl = '/api/tickets';

  listTickets(): Observable<Ticket[]> {
    return this.http.get<Ticket[]>(this.baseUrl);
  }

  createTicket(draft: TicketDraft): Observable<Ticket> {
    return this.http.post<Ticket>(this.baseUrl, draft);
  }
}

standalone 应用通常在 app.config.ts 中提供 HttpClient。

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes), provideHttpClient()],
};

常见失败是让 service 同时处理 UI 文案、重试策略和本地状态。service 应该保持朴素:负责端点、类型和通信,不负责“页面上怎么说”。

组合 standalone component 与 Reactive Forms

这个组件用 Reactive Forms 管理输入,用 signal 管理保存状态。让 Claude Code 生成时要明确“不要使用 ngModel”。

import { Component, computed, inject, signal } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';
import { finalize } from 'rxjs';
import { Ticket, TicketService, TicketPriority } from '../../../data/ticket.service';

@Component({
  selector: 'app-ticket-intake',
  standalone: true,
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="form" (ngSubmit)="submit()" aria-label="Support ticket form">
      <label>Title <input type="text" formControlName="title" /></label>
      <label>Email <input type="email" formControlName="email" /></label>
      <label>
        Priority
        <select formControlName="priority">
          <option value="low">Low</option>
          <option value="medium">Medium</option>
          <option value="high">High</option>
        </select>
      </label>
      <label>Message <textarea formControlName="message"></textarea></label>

      @if (form.hasError('submit')) {
        <p role="alert">Ticket could not be saved. Please try again.</p>
      }
      @if (savedTicket(); as ticket) {
        <p role="status">Saved ticket {{ ticket.id }}</p>
      }
      <button type="submit" [disabled]="isSubmitDisabled()">
        {{ saving() ? 'Saving...' : 'Create ticket' }}
      </button>
    </form>
  `,
})
export class TicketIntakeComponent {
  private readonly ticketService = inject(TicketService);
  readonly saving = signal(false);
  readonly savedTicket = signal<Ticket | null>(null);

  readonly form = new FormGroup({
    title: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.minLength(5)] }),
    email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }),
    priority: new FormControl<TicketPriority>('medium', { nonNullable: true }),
    message: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.minLength(20)] }),
  });

  readonly isSubmitDisabled = computed(() => this.form.invalid || this.saving());

  submit(): void {
    this.form.markAllAsTouched();
    this.form.setErrors(null);
    if (this.form.invalid) return;

    this.saving.set(true);
    this.ticketService.createTicket(this.form.getRawValue()).pipe(
      finalize(() => this.saving.set(false)),
    ).subscribe({
      next: (ticket) => {
        this.savedTicket.set(ticket);
        this.form.reset({ title: '', email: '', priority: 'medium', message: '' });
      },
      error: () => this.form.setErrors({ submit: true }),
    });
  }
}

容易踩坑的地方有三个:把 ngModelformControlName 混用;忘记在保存中禁用按钮;把可能包含 nullable 值的 form.value 直接发给 API。这里用 nonNullablegetRawValue() 可以减少类型漏洞。

三个以上的实际用例

第一个用例是后台录入表单。提示词要写字段、校验、提交中状态、成功和失败显示,而不是只说“做得专业一点”。

第二个用例是把组件里的 HTTP 请求抽成 service。让 Claude Code 添加接口类型、移动 HttpClient 调用、保留 UI 文案在组件中,并补上 HTTP 测试。

第三个用例是修复回归 bug。例如“请求失败后按钮一直 disabled”,要给出复现步骤、期望结果和测试命令,让 Claude Code 同时补失败路径测试。

第四个用例是从 NgModule 逐步迁移到 standalone。不要让它一次改完整个项目,可以限制在一个 feature 目录,保持 routing 和 provider 不动。

单元测试、E2E 与 review 指令

HttpClient 测试不能打真实网络。使用 Angular 的 testing backend 可以检查请求方法和请求体。

import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting, HttpTestingController } from '@angular/common/http/testing';
import { TicketService } from './ticket.service';

describe('TicketService', () => {
  let service: TicketService;
  let http: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [TicketService, provideHttpClient(), provideHttpClientTesting()],
    });
    service = TestBed.inject(TicketService);
    http = TestBed.inject(HttpTestingController);
  });

  afterEach(() => http.verify());

  it('creates a ticket through the API', () => {
    const draft = {
      title: 'Billing export is stuck',
      email: 'ops@example.com',
      priority: 'high' as const,
      message: 'The monthly billing export has not finished for two hours.',
    };

    service.createTicket(draft).subscribe((ticket) => expect(ticket.id).toBe('T-100'));
    const req = http.expectOne('/api/tickets');
    expect(req.request.method).toBe('POST');
    expect(req.request.body).toEqual(draft);
    req.flush({ ...draft, id: 'T-100', createdAt: '2026-06-02T09:00:00.000Z' });
  });
});

E2E 方面,如果项目有 Angular CLI 的 E2E target,可以跑 ng e2e;如果团队使用 Playwright,就用受控 API 响应检查完整用户路径。

请批判性 review 这次 Angular 差异。
检查 standalone imports/provider、Reactive Forms nullable 值、二次提交、
service 是否混入 UI 职责、HttpClient 测试是否打真实网络、
unit/E2E 是否覆盖失败路径、是否出现 any 和可访问性问题。
请按优先级列出文件名和行号。

结论和实测结果

Claude Code 很适合加速 Angular 开发,但前提是任务被拆小。推荐顺序是:读取项目、确认 CLI 和测试工具、写 typed service、写 standalone form、补 HttpClient test、补 E2E、最后做审查。

我在一个小型 Angular 验证项目中试过,两种提示词差异很明显。只说“帮我做一个表单”时,结果混入了 ngModel,没有失败路径测试,service 里还出现了 UI 文案。改成明确要求 Reactive Forms、provideHttpClientHttpTestingController、不允许 any 之后,主要修改点只剩文案和样式。需要团队导入时,可以把这些规则写入 CLAUDE.md,并从 Claude Code 培训与咨询 设计固定的 review 流程。

#Claude Code #Angular #TypeScript #frontend #enterprise
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。