Q21 of 48 · Cypress
How do you write a custom command in Cypress with TypeScript types?
Short answer
Short answer: Register the command with `Cypress.Commands.add(name, fn)` in `cypress/support/commands.ts`, then declare its type in a global `Cypress.Chainable` interface extension. The declaration gives autocomplete and type-checking inside specs.
Detail
Custom commands are how you encapsulate repeated test logic — login, add-to-cart, seed-state — into reusable verbs. The two-step pattern in TypeScript:
Step 1: Implement in cypress/support/commands.ts:
Cypress.Commands.add('loginAs', (role) => {
cy.session(role, () => {
cy.request('POST', '/api/login', { role });
});
});
Step 2: Declare types so TypeScript knows about the command:
declare global {
namespace Cypress {
interface Chainable {
loginAs(role: 'admin' | 'viewer' | 'guest'): Chainable<void>;
}
}
}
export {};
The export {} at the bottom makes the file a module so the global declaration is picked up; without it, the declare global is local to the file.
Two flavours of custom commands:
- Parent commands — start a new chain. Use
Cypress.Commands.add('name', fn)with noprevSubjectoption.cy.loginAs(...). - Child commands — operate on a previous subject. Use
Cypress.Commands.add('name', { prevSubject: 'element' }, fn).cy.get('input').clearAndType('text').
For a parent command that yields a value (chainable), wrap the return: return cy.wrap(value). The type signature should reflect what's yielded.
Custom commands belong in cypress/support/commands.ts (auto-loaded). Don't put them in spec files — they pollute the global cy and break type checking.
// EXAMPLE
cypress/support/commands.ts
// Implementation
Cypress.Commands.add('loginAs', (role: 'admin' | 'viewer') => {
cy.session(role, () => {
cy.request('POST', '/api/login', {
email: Cypress.env(`${role}Email`),
password: Cypress.env('password'),
});
});
});
Cypress.Commands.add(
'clearAndType',
{ prevSubject: 'element' },
(subject: JQuery<HTMLElement>, text: string) => {
cy.wrap(subject).clear().type(text);
},
);
// Type declaration
declare global {
namespace Cypress {
interface Chainable {
loginAs(role: 'admin' | 'viewer'): Chainable<void>;
clearAndType(text: string): Chainable<JQuery<HTMLElement>>;
}
}
}
export {};// WHAT INTERVIEWERS LOOK FOR
// COMMON PITFALL
// Related questions
How would you structure a Page Object Model in a TypeScript Cypress project?
Cypress
When would you use cy.session over a custom login command?
Cypress
How do you install and configure Playwright in a TypeScript project?
Playwright
How do you add type definitions for a custom Cypress command in TypeScript?
TypeScript