You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices.
- Use strict type checking
- Prefer type inference when the type is obvious
- Avoid the
anytype; useunknownwhen type is uncertain
- Always use standalone components over NgModules
- Must NOT set
standalone: trueinside Angular decorators. It's the default. - Use signals for state management
- Implement lazy loading for feature routes
- Do NOT use the
@HostBindingand@HostListenerdecorators. Put host bindings inside thehostobject of the@Componentor@Directivedecorator instead
- Keep components small and focused on a single responsibility
- Use
input()andoutput()functions instead of decorators - Use
computed()for derived state - Set
changeDetection: ChangeDetectionStrategy.OnPushin@Componentdecorator - Prefer inline templates for small components
- Prefer Reactive forms instead of Template-driven ones
- Do NOT use
ngClass, useclassbindings instead - Do NOT use
ngStyle, usestylebindings instead
- Test through the component's public API and rendered DOM, not private methods or internal implementation details
- Prefer creating the component directly with
TestBed. Use signalinputBindingandoutputBindingbindings instead of test host / wrapper components when wiring inputs and outputs - Only introduce a test host / wrapper component when testing content projection, template composition, or integration behavior that cannot be expressed through direct bindings
- Keep test setup minimal. Mock only the component's direct dependencies and prefer lightweight spies or stubs over large testing modules
- Prefer assertions on user-observable behavior such as rendered text, attributes, ARIA state, CSS classes that are part of the public contract, and emitted outputs
- Prefer
await fixture.whenStable()after interactions or async state changes instead of repeatedly callingfixture.detectChanges(). Usefixture.detectChanges()deliberately for the initial render or when the change detection boundary itself is under test - Keep each test focused on a single behavior with clear arrange / act / assert phases
- Cover happy paths, boundary conditions, and regression-prone branches. Avoid broad snapshot-style assertions that do not explain the intended behavior
- Prefer
await fixture.whenStable()over repeatedfixture.detectChanges()calls after interactions or async state changes whenStable()waits for pending microtasks, timers, and zone activity to settle, producing more reliable tests than manually pumping change detection- Use
fixture.detectChanges()deliberately for the initial render or when the change detection boundary itself is under test - Do NOT chain multiple
detectChanges()calls hoping to flush async work — usewhenStable()instead
- Prefer Vitest's semantic assertion matchers over generic
.toBe()with manual property access — they produce clearer failure messages and more readable tests - Use
toHaveLength(n)instead of accessing.lengthmanually:expect(items).toHaveLength(3)notexpect(items.length).toBe(3) - Use
toContain(item)instead ofexpect(array.includes(item)).toBe(true) - Use
toMatchObject(subset)to assert on a subset of properties instead of multiple individual.toBe()assertions
- Use signals for local component state
- Use
computed()for derived state - Keep state transformations pure and predictable
- Do NOT use
mutateon signals, useupdateorsetinstead
- Keep templates simple and avoid complex logic
- Use native control flow (
@if,@for,@switch) instead of*ngIf,*ngFor,*ngSwitch - Use the async pipe to handle observables
- Design services around a single responsibility
- Use the
providedIn: 'root'option for singleton services - Use the
inject()function instead of constructor injection
The live-preview demo app runs on http://localhost:4200/.
If not online, ask to start the server. Do not run it yourself.
Load examples using this URL schema:
http://localhost:4200/#/viewer/preview?e=<relative-example-path>
<relative-example-path> is resolved against examplesBaseUrl (app/examples/, see src/app/app.config.ts:132) and omits the file extension.
Example for si-form:
http://localhost:4200/#/viewer/preview?e=si-form/si-form
Supported query params (see projects/live-preview/components/si-example-viewer/si-example-viewer.component.ts)
Unless specifically requested, only use the example path.
e— example pathbase— prefix prepended to eachetheme—light|darklocale— e.g.en,deisRTL— truthy for RTLmode— device mode for mobile viewportrfs— root font size in pxt— inline template overrideframework—react|vue|js