{
  "doc": {
    "id": "app/tooling/typescript-support",
    "title": "TypeScript support in Cypress",
    "description": "Learn how to set up TypeScript in Cypress, configure TypeScript for custom commands, assertions, and plugins and more",
    "section": "app",
    "source_path": "/llm/markdown/app/tooling/typescript-support.md",
    "version": "fbc9225067c51c52ee13224e3b702cf8a025ec12",
    "updated_at": "2026-08-14T12:36:26.878Z",
    "headings": [
      {
        "id": "app/tooling/typescript-support#typescript-support",
        "text": "TypeScript Support",
        "level": 1
      },
      {
        "id": "app/tooling/typescript-support#why-typescript-with-cypress",
        "text": "Why TypeScript with Cypress?",
        "level": 2
      },
      {
        "id": "app/tooling/typescript-support#catch-errors-at-the-editor-not-in-ci",
        "text": "Catch errors at the editor, not in CI",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#intellisense-makes-the-api-self-documenting",
        "text": "IntelliSense makes the API self-documenting",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#safer-refactoring-across-the-codebase",
        "text": "Safer refactoring across the codebase",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#lower-cost-of-onboarding-and-review",
        "text": "Lower cost of onboarding and review",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#shared-types-between-app-code-and-tests",
        "text": "Shared types between app code and tests",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#get-started",
        "text": "Get Started",
        "level": 2
      },
      {
        "id": "app/tooling/typescript-support#install-typescript",
        "text": "Install TypeScript",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#configure-tsconfig-json",
        "text": "Configure tsconfig.json",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#processing-your-cypress-configuration-and-plugins",
        "text": "Processing your Cypress configuration and plugins",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#align-tsconfig-json-with-your-module-format",
        "text": "Align tsconfig.json with your module format",
        "level": 4
      },
      {
        "id": "app/tooling/typescript-support#extending-typescript-support",
        "text": "Extending TypeScript Support",
        "level": 2
      },
      {
        "id": "app/tooling/typescript-support#types-for-custom-commands",
        "text": "Types for Custom Commands",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#declare-global-requires-a-typescript-module-file",
        "text": "declare global requires a TypeScript module file",
        "level": 4
      },
      {
        "id": "app/tooling/typescript-support#adding-child-or-dual-commands",
        "text": "Adding child or dual commands",
        "level": 4
      },
      {
        "id": "app/tooling/typescript-support#overwriting-child-or-dual-commands",
        "text": "Overwriting child or dual commands",
        "level": 4
      },
      {
        "id": "app/tooling/typescript-support#examples",
        "text": "Examples:",
        "level": 4
      },
      {
        "id": "app/tooling/typescript-support#types-for-custom-queries",
        "text": "Types for Custom Queries",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#types-for-custom-window-properties",
        "text": "Types for custom window properties",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#types-for-custom-assertions",
        "text": "Types for custom assertions",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#types-for-plugins",
        "text": "Types for plugins",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#using-an-external-typings-file",
        "text": "Using an External Typings File",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#ambient-declaration-file-no-imports-needed",
        "text": "Ambient declaration file (no imports needed)",
        "level": 4
      },
      {
        "id": "app/tooling/typescript-support#file-with-imports-e-g-cy-mount",
        "text": "File with imports (e.g. cy.mount)",
        "level": 4
      },
      {
        "id": "app/tooling/typescript-support#set-up-your-dev-environment",
        "text": "Set up your dev environment",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#clashing-types-with-jest",
        "text": "Clashing types with Jest",
        "level": 3
      },
      {
        "id": "app/tooling/typescript-support#history",
        "text": "History",
        "level": 2
      },
      {
        "id": "app/tooling/typescript-support#see-also",
        "text": "See also",
        "level": 2
      }
    ]
  },
  "chunks": [
    {
      "id": "app/tooling/typescript-support#why-typescript-with-cypress",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Why TypeScript with Cypress?",
      "heading_level": 2,
      "content_markdown": "## Why TypeScript with Cypress?\n\nWriting Cypress tests in TypeScript gives your team a tight feedback loop that catches problems before a single browser opens — and long before a bug reaches production.\n\n### Catch errors at the editor, not in CI\n\nTypeScript surfaces mismatched selectors, wrong argument types, and missing return values as red underlines in your editor the moment you type them. Without TypeScript, those same mistakes surface as a failing test run minutes or hours later — or worse, a bug reported by a user. Moving that feedback earlier eliminates a whole class of debugging cycles.\n\n### IntelliSense makes the API self-documenting\n\nWhen your test file is TypeScript, your editor can autocomplete every `cy.*` command, show its accepted parameters, and display the inline JSDoc as you type. Your team spends less time reading reference docs and less time guessing whether the third argument is optional. For custom commands you expose to the rest of the team, typed declarations act as a lightweight contract: the name, parameters, and return type are machine-verified so callers always get correct usage.\n\n### Safer refactoring across the codebase\n\nWhen a selector utility, a fixture type, or a page-object method changes, the TypeScript compiler points to every test that is now broken — across the entire project — before you run anything. On a large team, this makes refactoring a planned, predictable operation rather than a game of grep-and-hope.\n\n### Lower cost of onboarding and review\n\nNew engineers can explore the test suite with editor assistance rather than reading every helper file to understand what it does. Code reviewers can focus on intent rather than hunting for type mismatches. Both effects compound over time: less ramp-up cost, fewer back-and-forth review cycles, and a test suite that stays readable as it grows.\n\n### Shared types between app code and tests\n\nBecause your Cypress support files are plain TypeScript, they can import the same type definitions your application uses — API response shapes, domain models, enum values. A type change in the app propagates into the tests automatically, so your tests stay aligned with the code they exercise without manual synchronization.\n",
      "section": "app",
      "anchors": [
        "why-typescript-with-cypress"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 475
    },
    {
      "id": "app/tooling/typescript-support#catch-errors-at-the-editor-not-in-ci",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Catch errors at the editor, not in CI",
      "heading_level": 3,
      "content_markdown": "### Catch errors at the editor, not in CI\n\nTypeScript surfaces mismatched selectors, wrong argument types, and missing return values as red underlines in your editor the moment you type them. Without TypeScript, those same mistakes surface as a failing test run minutes or hours later — or worse, a bug reported by a user. Moving that feedback earlier eliminates a whole class of debugging cycles.\n",
      "section": "app",
      "anchors": [
        "catch-errors-at-the-editor-not-in-ci"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 88
    },
    {
      "id": "app/tooling/typescript-support#intellisense-makes-the-api-self-documenting",
      "doc_id": "app/tooling/typescript-support",
      "heading": "IntelliSense makes the API self-documenting",
      "heading_level": 3,
      "content_markdown": "### IntelliSense makes the API self-documenting\n\nWhen your test file is TypeScript, your editor can autocomplete every `cy.*` command, show its accepted parameters, and display the inline JSDoc as you type. Your team spends less time reading reference docs and less time guessing whether the third argument is optional. For custom commands you expose to the rest of the team, typed declarations act as a lightweight contract: the name, parameters, and return type are machine-verified so callers always get correct usage.\n",
      "section": "app",
      "anchors": [
        "intellisense-makes-the-api-self-documenting"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 108
    },
    {
      "id": "app/tooling/typescript-support#safer-refactoring-across-the-codebase",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Safer refactoring across the codebase",
      "heading_level": 3,
      "content_markdown": "### Safer refactoring across the codebase\n\nWhen a selector utility, a fixture type, or a page-object method changes, the TypeScript compiler points to every test that is now broken — across the entire project — before you run anything. On a large team, this makes refactoring a planned, predictable operation rather than a game of grep-and-hope.\n",
      "section": "app",
      "anchors": [
        "safer-refactoring-across-the-codebase"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 75
    },
    {
      "id": "app/tooling/typescript-support#lower-cost-of-onboarding-and-review",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Lower cost of onboarding and review",
      "heading_level": 3,
      "content_markdown": "### Lower cost of onboarding and review\n\nNew engineers can explore the test suite with editor assistance rather than reading every helper file to understand what it does. Code reviewers can focus on intent rather than hunting for type mismatches. Both effects compound over time: less ramp-up cost, fewer back-and-forth review cycles, and a test suite that stays readable as it grows.\n",
      "section": "app",
      "anchors": [
        "lower-cost-of-onboarding-and-review"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 83
    },
    {
      "id": "app/tooling/typescript-support#shared-types-between-app-code-and-tests",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Shared types between app code and tests",
      "heading_level": 3,
      "content_markdown": "### Shared types between app code and tests\n\nBecause your Cypress support files are plain TypeScript, they can import the same type definitions your application uses — API response shapes, domain models, enum values. A type change in the app propagates into the tests automatically, so your tests stay aligned with the code they exercise without manual synchronization.\n",
      "section": "app",
      "anchors": [
        "shared-types-between-app-code-and-tests"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 77
    },
    {
      "id": "app/tooling/typescript-support#get-started",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Get Started",
      "heading_level": 2,
      "content_markdown": "## Get Started\n\n### Install TypeScript\n\nTo use TypeScript with Cypress, you will need TypeScript 5.x, 6.x, or 7.x. If you do not already have TypeScript installed as a part of your framework, you will need to install it:\n\n*   npm\n*   yarn\n*   pnpm\n*   bun\n\n```\nnpm install typescript --save-dev\n```\n\n```\nyarn add typescript --dev\n```\n\n```\npnpm add --save-dev typescript\n```\n\n```\nbun add --dev typescript\n```\n\n### Configure tsconfig.json\n\nWe recommend creating a [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) inside your [`cypress` folder](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Project-structure) with the following configuration:\n\ntsconfig.json\n\n```\n{  \"compilerOptions\": {    \"target\": \"es6\",    \"lib\": [\"es6\", \"dom\"],    \"sourceMap\": true,    \"types\": [\"cypress\", \"node\"]  },  \"include\": [\"**/*.ts\"]}\n```\n\nThe `\"types\"` will tell the TypeScript compiler to only include type definitions from Cypress. This will address instances where the project also uses `@types/chai` or `@types/jquery`. Since [Chai](/llm/markdown/app/references/bundled-libraries.md#Chai) and [jQuery](/llm/markdown/app/references/bundled-libraries.md#Utility-libraries) are namespaces (globals), incompatible versions will cause the package manager (`yarn` or `npm`) to nest and include multiple definitions and cause conflicts.\n\nYou may have to restart your IDE's TypeScript server if the setup above does not appear to work. For example:\n\nVS Code (within a .ts or .js file):\n\n*   Open the command palette (Mac: `cmd+shift+p`, Windows: `ctrl+shift+p`)\n*   Type \"restart ts\" and select the \"TypeScript: Restart TS server.\" option\n\nIf that does not work, try restarting the IDE.\n\n### Processing your Cypress configuration and plugins\n\nCypress supports TypeScript configuration files with `.ts`, `.mts`, and `.cts` extensions. Under the hood, Cypress uses [tsx](https://tsx.is/) to transpile and run them inside the Cypress runtime without being bound to limitations of Node or other loaders.\n\nWhether a TypeScript config loads as ESM or CommonJS follows the same [Node.js module rules](/llm/markdown/app/references/configuration.md#ESM-vs-CommonJS) as JavaScript configs. Use `.mts` and `.cts` the same way you would use `.mjs` and `.cjs` — to force ESM or CommonJS regardless of `package.json` `\"type\"`.\n\n#### Align `tsconfig.json` with your module format\n\nCypress does not use `compilerOptions.module` when deciding how to load your config — that comes from the file extension and nearest `package.json` `\"type\"`. Your `tsconfig.json` should still align so TypeScript and your editor match how Cypress runs the file:\n\n**CommonJS** — set `compilerOptions.module` to `\"commonjs\"`, then either:\n\n*   name the config `cypress.config.cts`, or\n*   use `cypress.config.ts` with `package.json` `\"type\"` omitted or set to `\"commonjs\"`\n\n**ESM** — set `compilerOptions.module` to an ESM-compatible option (for example `\"NodeNext\"` or `\"ES2022\"`), then either:\n\n*   set `package.json` `\"type\"` to `\"module\"` and use `cypress.config.ts`, or\n*   name the config `cypress.config.mts`\n\n`import` and `export` syntax in a `.ts` config does not by itself mean the file loads as ESM. With `compilerOptions.module` set to `\"commonjs\"`, TypeScript transpiles those statements to `require()` and `module.exports` — so you can use `import` in a config that Cypress loads as CommonJS. What matters is the alignment between `compilerOptions.module`, your config file extension, and `package.json` `\"type\"`.\n",
      "section": "app",
      "anchors": [
        "get-started"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 613
    },
    {
      "id": "app/tooling/typescript-support#install-typescript",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Install TypeScript",
      "heading_level": 3,
      "content_markdown": "### Install TypeScript\n\nTo use TypeScript with Cypress, you will need TypeScript 5.x, 6.x, or 7.x. If you do not already have TypeScript installed as a part of your framework, you will need to install it:\n\n*   npm\n*   yarn\n*   pnpm\n*   bun\n\n```\nnpm install typescript --save-dev\n```\n\n```\nyarn add typescript --dev\n```\n\n```\npnpm add --save-dev typescript\n```\n\n```\nbun add --dev typescript\n```\n",
      "section": "app",
      "anchors": [
        "install-typescript"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 91
    },
    {
      "id": "app/tooling/typescript-support#configure-tsconfig-json",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Configure tsconfig.json",
      "heading_level": 3,
      "content_markdown": "### Configure tsconfig.json\n\nWe recommend creating a [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) inside your [`cypress` folder](/llm/markdown/app/core-concepts/writing-and-organizing-tests.md#Project-structure) with the following configuration:\n\ntsconfig.json\n\n```\n{  \"compilerOptions\": {    \"target\": \"es6\",    \"lib\": [\"es6\", \"dom\"],    \"sourceMap\": true,    \"types\": [\"cypress\", \"node\"]  },  \"include\": [\"**/*.ts\"]}\n```\n\nThe `\"types\"` will tell the TypeScript compiler to only include type definitions from Cypress. This will address instances where the project also uses `@types/chai` or `@types/jquery`. Since [Chai](/llm/markdown/app/references/bundled-libraries.md#Chai) and [jQuery](/llm/markdown/app/references/bundled-libraries.md#Utility-libraries) are namespaces (globals), incompatible versions will cause the package manager (`yarn` or `npm`) to nest and include multiple definitions and cause conflicts.\n\nYou may have to restart your IDE's TypeScript server if the setup above does not appear to work. For example:\n\nVS Code (within a .ts or .js file):\n\n*   Open the command palette (Mac: `cmd+shift+p`, Windows: `ctrl+shift+p`)\n*   Type \"restart ts\" and select the \"TypeScript: Restart TS server.\" option\n\nIf that does not work, try restarting the IDE.\n",
      "section": "app",
      "anchors": [
        "configure-tsconfig-json"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 193
    },
    {
      "id": "app/tooling/typescript-support#processing-your-cypress-configuration-and-plugins",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Processing your Cypress configuration and plugins",
      "heading_level": 3,
      "content_markdown": "### Processing your Cypress configuration and plugins\n\nCypress supports TypeScript configuration files with `.ts`, `.mts`, and `.cts` extensions. Under the hood, Cypress uses [tsx](https://tsx.is/) to transpile and run them inside the Cypress runtime without being bound to limitations of Node or other loaders.\n\nWhether a TypeScript config loads as ESM or CommonJS follows the same [Node.js module rules](/llm/markdown/app/references/configuration.md#ESM-vs-CommonJS) as JavaScript configs. Use `.mts` and `.cts` the same way you would use `.mjs` and `.cjs` — to force ESM or CommonJS regardless of `package.json` `\"type\"`.\n\n#### Align `tsconfig.json` with your module format\n\nCypress does not use `compilerOptions.module` when deciding how to load your config — that comes from the file extension and nearest `package.json` `\"type\"`. Your `tsconfig.json` should still align so TypeScript and your editor match how Cypress runs the file:\n\n**CommonJS** — set `compilerOptions.module` to `\"commonjs\"`, then either:\n\n*   name the config `cypress.config.cts`, or\n*   use `cypress.config.ts` with `package.json` `\"type\"` omitted or set to `\"commonjs\"`\n\n**ESM** — set `compilerOptions.module` to an ESM-compatible option (for example `\"NodeNext\"` or `\"ES2022\"`), then either:\n\n*   set `package.json` `\"type\"` to `\"module\"` and use `cypress.config.ts`, or\n*   name the config `cypress.config.mts`\n\n`import` and `export` syntax in a `.ts` config does not by itself mean the file loads as ESM. With `compilerOptions.module` set to `\"commonjs\"`, TypeScript transpiles those statements to `require()` and `module.exports` — so you can use `import` in a config that Cypress loads as CommonJS. What matters is the alignment between `compilerOptions.module`, your config file extension, and `package.json` `\"type\"`.\n",
      "section": "app",
      "anchors": [
        "processing-your-cypress-configuration-and-plugins"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 325
    },
    {
      "id": "app/tooling/typescript-support#align-tsconfig-json-with-your-module-format",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Align tsconfig.json with your module format",
      "heading_level": 4,
      "content_markdown": "#### Align `tsconfig.json` with your module format\n\nCypress does not use `compilerOptions.module` when deciding how to load your config — that comes from the file extension and nearest `package.json` `\"type\"`. Your `tsconfig.json` should still align so TypeScript and your editor match how Cypress runs the file:\n\n**CommonJS** — set `compilerOptions.module` to `\"commonjs\"`, then either:\n\n*   name the config `cypress.config.cts`, or\n*   use `cypress.config.ts` with `package.json` `\"type\"` omitted or set to `\"commonjs\"`\n\n**ESM** — set `compilerOptions.module` to an ESM-compatible option (for example `\"NodeNext\"` or `\"ES2022\"`), then either:\n\n*   set `package.json` `\"type\"` to `\"module\"` and use `cypress.config.ts`, or\n*   name the config `cypress.config.mts`\n\n`import` and `export` syntax in a `.ts` config does not by itself mean the file loads as ESM. With `compilerOptions.module` set to `\"commonjs\"`, TypeScript transpiles those statements to `require()` and `module.exports` — so you can use `import` in a config that Cypress loads as CommonJS. What matters is the alignment between `compilerOptions.module`, your config file extension, and `package.json` `\"type\"`.\n",
      "section": "app",
      "anchors": [
        "align-tsconfig-json-with-your-module-format"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 213
    },
    {
      "id": "app/tooling/typescript-support#extending-typescript-support",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Extending TypeScript Support",
      "heading_level": 2,
      "content_markdown": "## Extending TypeScript Support\n\n### Types for Custom Commands\n\nWhen adding [custom commands](/llm/markdown/api/cypress-api/custom-commands.md) to the `cy` object, you can manually add their types to avoid TypeScript errors.\n\nFor example, if you add the command `cy.dataCy` to `cypress/support/commands.ts` (which is imported by your [support entry file](/llm/markdown/app/references/configuration.md#Testing-Type-Specific-Options) `cypress/support/e2e.ts`) like this:\n\ncypress/support/commands.ts\n\n```\nCypress.Commands.add('dataCy', (value) => {  return cy.get(`[data-cy=${value}]`)})\n```\n\nThen you can add the `dataCy` command to the global Cypress Chainable interface (so called because commands are chained together).\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      /**       * Custom command to select DOM element by data-cy attribute.       * @example cy.dataCy('greeting')       */      dataCy(value: string): Chainable<JQuery<HTMLElement>>    }  }}\n```\n\n#### `declare global` requires a TypeScript module file\n\nTypeScript distinguishes between two kinds of files:\n\n*   **Module** — any file with at least one top-level `import` or `export` statement\n*   **Script (ambient)** — a file with no imports or exports\n\n`declare global { ... }` is only valid inside a **module** file. If your `commands.ts` has no imports, TypeScript will raise an error such as: _\"Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.\"_\n\nThe simplest fix is to add `export {}` at the bottom of the file so TypeScript treats it as a module:\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      dataCy(value: string): Chainable<JQuery<HTMLElement>>    }  }}export {} // turns this file into a module so declare global is valid\n```\n\nAlternatively, move your type declarations into a standalone [external typings file](#Using-an-External-Typings-File) where no `import` or `export` is needed.\n\nConversely, if you use `declare namespace Cypress { ... }` **without** the `declare global` wrapper inside a file that _does_ have imports, TypeScript will **not** augment the global `Cypress` namespace — your custom commands will still appear as unknown.\n\nA nice detailed JSDoc comment above the method type will be really appreciated by any users of your custom command.\n\nTypes of all the parameters taken by the implementation callback are inferred automatically based on the declared interface. Thus, in the example above, the `value` will be of type `string` implicitly.\n\nIn your specs, you can now use the custom command as expected\n\n*   End-to-End Test\n*   Component Test\n\n```\nit('works', () => {  // from your cypress/e2e/spec.cy.ts  cy.visit('/')  // IntelliSense and TS compiler should  // not complain about unknown method  cy.dataCy('greeting')})\n```\n\n```\nit('works', () => {  // from your src/components/MyComponent.cy.ts  cy.mount(<MyComponent />)  // IntelliSense and TS compiler should  // not complain about unknown method  cy.dataCy('greeting')})\n```\n\n#### Adding child or dual commands\n\nWhen you add a custom command with `prevSubject`, Cypress will infer the subject type automatically based on the specified `prevSubject`.\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      /**       * Custom command to type a few random words into input elements       * @param count=3       * @example cy.get('input').typeRandomWords()       */      typeRandomWords(        count?: number,        options?: Partial<TypeOptions>      ): Chainable<JQuery<HTMLElement>>    }  }}\n```\n\ncypress/support/commands.ts\n\n```\nCypress.Commands.add(  'typeRandomWords',  { prevSubject: 'element' },  (subject /* :JQuery<HTMLElement> */, count = 3, options?) => {    return cy.wrap(subject).type(generateRandomWords(count), options)  })\n```\n\n#### Overwriting child or dual commands\n\nWhen overwriting either built-in or custom commands which make use of `prevSubject`, you must specify generic parameters to help the type-checker to understand the type of the `prevSubject`.\n\ncypress/support/commands.ts\n\n```\ninterface TypeOptions extends Cypress.TypeOptions {  sensitive: boolean}Cypress.Commands.overwrite<'type', 'element'>(  'type',  (originalFn, element, text, options?: Partial<TypeOptions>) => {    if (options && options.sensitive) {      // turn off original log      options.log = false      // create our own log with masked message      Cypress.log({        $el: element,        name: 'type',        message: '*'.repeat(text.length),      })    }    return originalFn(element, text, options)  })\n```\n\nAs you can see there are generic parameters `<'type', 'element'>` are used:\n\n1.  The first parameter is the command name, equal to first parameter passed to `Cypress.Commands.overwrite`.\n2.  The second parameter is the type of the `prevSubject` that is used by the original command. Possible values:\n    *   'element' infers it as `JQuery<HTMLElement>`\n    *   'window' infers it as `Window`\n    *   'document' infers it as `Document`\n    *   'optional' infers it as `unknown`\n\n#### Examples:\n\n*   See [Adding Custom Commands (TS)](https://github.com/cypress-io/cypress-example-recipes#fundamentals) example recipe.\n\n### Types for Custom Queries\n\nWhen adding [custom queries](/llm/markdown/api/cypress-api/custom-queries.md) with `Cypress.Commands.addQuery()`, you must declare the query on the `Chainable` interface **before** registering it. Cypress infers the query callback's argument types from that declaration.\n\nUnlike custom commands, query callbacks receive `this` as a `Cypress.Command` (not `Mocha.Context`), and the callback must return an inner function that performs the query synchronously.\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      /**       * Gets the currently focused DOM element.       * @example cy.focused2()       */      focused2(        options?: Partial<Cypress.Loggable & Cypress.Timeoutable>      ): Chainable<JQuery>    }    // Required so this.set('timeout', ...) type-checks in query callbacks    interface EnqueuedCommandAttributes {      timeout?: number    }  }}Cypress.Commands.addQuery(  'focused2',  function focused2(    options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}  ) {    const log =      options.log !== false &&      Cypress.log({        ...(options.timeout !== undefined && { timeout: options.timeout }),      })    this.set('timeout', options.timeout)    return () => {      let $el = cy.getFocused()      // ...      return $el    }  })\n```\n\nWhen passing optional `timeout` to `Cypress.log()`, avoid writing `{ timeout: options.timeout }` directly if `options.timeout` may be `undefined`. With strict TypeScript settings such as `exactOptionalPropertyTypes`, explicitly passing `undefined` is not assignable to an optional property. Use a conditional spread instead, as shown above.\n\nFor queries that accept additional options, combine the relevant Cypress option interfaces with `Partial<>`, matching how built-in queries are typed. For example, a query with timeout and shadow DOM support might use `Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.Shadow>`.\n\nTo overwrite an existing query, declare the query on `Chainable` as usual and use `Cypress.Commands.overwriteQuery()`. The first argument to your callback is the original query function:\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      get(        selector: string,        options?: Partial<Cypress.Loggable & Cypress.Timeoutable>      ): Chainable<JQuery<HTMLElement>>    }  }}Cypress.Commands.overwriteQuery('get', function (originalFn, ...args) {  return originalFn.apply(this, args)})\n```\n\n### Types for custom window properties\n\n[`cy.window()`](/llm/markdown/api/commands/window.md) yields an `AUTWindow` object, which is typed as `Window & typeof globalThis & Cypress.ApplicationWindow`. The `Cypress.ApplicationWindow` interface is an empty extension point that you can augment to tell TypeScript about properties your application adds to `window`.\n\nExtend the interface in your support file or a `*.d.ts` file:\n\ncypress/support/e2e.ts\n\n```\ndeclare global {  namespace Cypress {    interface ApplicationWindow {      // add the properties your app sets on window      env: {        DISABLE: boolean      }    }  }}\n```\n\nTypeScript will now recognize those properties inside `cy.window()` callbacks:\n\n```\ncy.window().then((win) => {  win.env.DISABLE = true // no TypeScript error})\n```\n\n### Types for custom assertions\n\nIf you extend Cypress assertions, you can extend the assertion types to make the TypeScript compiler understand the new methods. See the [Recipe: Adding Chai Assertions](/llm/markdown/app/references/recipes.md#Fundamentals) for instructions.\n\n### Types for plugins\n\nWhen using [`defineConfig`](/llm/markdown/app/references/configuration.md) in your `cypress.config.ts` file, TypeScript types for [`setupNodeEvents`](/llm/markdown/app/references/configuration.md#setupNodeEvents) are inferred automatically — no additional annotation is needed:\n\ncypress.config.ts\n\n```\nimport { defineConfig } from 'cypress'export default defineConfig({  e2e: {    setupNodeEvents(on, config) {      // implement node event listeners here    },  },})\n```\n\nIf you extract your plugin setup into a separate function or file, you can annotate it with the `Cypress.PluginConfig` type:\n\ncypress/plugins/index.ts\n\n```\nconst setupNodeEvents: Cypress.PluginConfig = (on, config) => {  // implement node event listeners here}export default setupNodeEvents\n```\n\n### Using an External Typings File\n\nYou might find it easier to organize your types by moving them from the support file into an external [declaration (\\*.d.ts) file](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html). To do so, create a new file, like _cypress.d.ts_, and cut the types for your custom commands/assertions from the _support_ file and into the new file.\n\n#### Ambient declaration file (no imports needed)\n\nA plain `.d.ts` file with no `import` or `export` statements is treated by TypeScript as an _ambient script_. In this context you can declare the namespace **directly** — the `declare global` wrapper is not required:\n\n*   cypress/support/commands.d.ts\n\n```\n// No imports — TypeScript treats this as an ambient declaration file.// Declare the namespace directly (no declare global wrapper needed).declare namespace Cypress {  interface Chainable {    /**     * Custom command to select DOM element by data-cy attribute.     * @example cy.dataCy('greeting')     */    dataCy(value: string): Chainable<JQuery<HTMLElement>>  }}\n```\n\nIf TypeScript does not resolve Cypress types automatically (for example when the `types` field in your `tsconfig.json` does not include `\"cypress\"`), add a triple-slash reference at the top of the declaration file:\n\n```\n/// <reference types=\"cypress\" />\n```\n\n#### File with imports (e.g. `cy.mount`)\n\nWhen the declaration file imports something — such as `cy.mount` for component testing — the `import` turns it into a TypeScript module and `declare global` is required:\n\n*   cypress.d.ts\n\n```\nimport { mount } from 'cypress/react'// Augment the Cypress namespace to include type definitions for// your custom command.// Alternatively, can be defined in cypress/support/component.d.ts// with a <reference path=\"./component\" /> at the top of your spec.declare global {  namespace Cypress {    interface Chainable {      mount: typeof mount    }  }}\n```\n\nYou might need to include the _\\*.d.ts_ in the include options in any _tsconfig.json_ files in your project for TypeScript to pick up the new types:\n\n*   tsconfig.json\n\n```\n\"include\": [  \"src\",  \"./cypress.d.ts\"]\n```\n\n*   ./cypress/tsconfig.json\n\n```\n\"include\": [  \"**/*.ts\",  \"../cypress.d.ts\"]\n```\n\n**TypeScript must be able to find the declaration file**\n\nIf you rename or move a declaration file, verify that its path is covered by the `include` globs in every `tsconfig.json` that needs to see it. A common mistake is placing a `global.d.ts` inside `cypress/support/` while the `cypress/tsconfig.json` only includes `**/*.ts` — `.d.ts` files are matched by `**/*.ts` only if the glob is `**/*.{ts,d.ts}` or simply `**/*`. Safest practice: list the file explicitly or use `\"include\": [\"**/*.ts\", \"**/*.d.ts\"]`.\n\n### Set up your dev environment\n\nPlease refer to your code editor in [TypeScript's Editor Support doc](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support) and follow the instructions for your IDE to get TypeScript support and [intelligent code completion](/llm/markdown/app/tooling/IDE-integration.md#Intelligent-Code-Completion) configured in your developer environment before continuing. TypeScript support is built in for [Visual Studio Code](https://code.visualstudio.com/), [Visual Studio](https://www.visualstudio.com/), and [WebStorm](https://www.jetbrains.com/webstorm/) - all other editors require extra setup.\n\n### Clashing types with Jest\n\nIf you are using both Jest and Cypress in the same project, the TypeScript types registered globally by the two test runners can clash. For example, both Jest and Cypress provide the clashing types for the `describe` and `it` functions. Both Jest and Expect (bundled inside Cypress) provide the clashing types for the `expect` assertion, etc.\n\nThe recommended solution is to use **separate `tsconfig.json` files** for your Jest tests and your Cypress tests.\n\n**Step 1:** Create (or ensure you have) a `cypress/tsconfig.json` that explicitly limits types to only what Cypress needs:\n\ncypress/tsconfig.json\n\n```\n{  \"compilerOptions\": {    \"target\": \"es6\",    \"lib\": [\"es6\", \"dom\"],    \"sourceMap\": true,    \"types\": [\"cypress\", \"node\"]  },  \"include\": [\"**/*.ts\"]}\n```\n\n**Step 2:** Exclude the `cypress` folder (and `cypress.config.ts`) from your root `tsconfig.json` so that Jest does not pick up Cypress global types:\n\ntsconfig.json\n\n```\n{  \"exclude\": [\"cypress.config.ts\", \"cypress\", \"node_modules\"]}\n```\n\nWith this setup, Jest uses the root `tsconfig.json` (without Cypress types) and Cypress uses its own `cypress/tsconfig.json` (with Cypress types), so the two sets of globals no longer interfere with each other.\n",
      "section": "app",
      "anchors": [
        "extending-typescript-support"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 2411
    },
    {
      "id": "app/tooling/typescript-support#types-for-custom-commands",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Types for Custom Commands",
      "heading_level": 3,
      "content_markdown": "### Types for Custom Commands\n\nWhen adding [custom commands](/llm/markdown/api/cypress-api/custom-commands.md) to the `cy` object, you can manually add their types to avoid TypeScript errors.\n\nFor example, if you add the command `cy.dataCy` to `cypress/support/commands.ts` (which is imported by your [support entry file](/llm/markdown/app/references/configuration.md#Testing-Type-Specific-Options) `cypress/support/e2e.ts`) like this:\n\ncypress/support/commands.ts\n\n```\nCypress.Commands.add('dataCy', (value) => {  return cy.get(`[data-cy=${value}]`)})\n```\n\nThen you can add the `dataCy` command to the global Cypress Chainable interface (so called because commands are chained together).\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      /**       * Custom command to select DOM element by data-cy attribute.       * @example cy.dataCy('greeting')       */      dataCy(value: string): Chainable<JQuery<HTMLElement>>    }  }}\n```\n\n#### `declare global` requires a TypeScript module file\n\nTypeScript distinguishes between two kinds of files:\n\n*   **Module** — any file with at least one top-level `import` or `export` statement\n*   **Script (ambient)** — a file with no imports or exports\n\n`declare global { ... }` is only valid inside a **module** file. If your `commands.ts` has no imports, TypeScript will raise an error such as: _\"Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.\"_\n\nThe simplest fix is to add `export {}` at the bottom of the file so TypeScript treats it as a module:\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      dataCy(value: string): Chainable<JQuery<HTMLElement>>    }  }}export {} // turns this file into a module so declare global is valid\n```\n\nAlternatively, move your type declarations into a standalone [external typings file](#Using-an-External-Typings-File) where no `import` or `export` is needed.\n\nConversely, if you use `declare namespace Cypress { ... }` **without** the `declare global` wrapper inside a file that _does_ have imports, TypeScript will **not** augment the global `Cypress` namespace — your custom commands will still appear as unknown.\n\nA nice detailed JSDoc comment above the method type will be really appreciated by any users of your custom command.\n\nTypes of all the parameters taken by the implementation callback are inferred automatically based on the declared interface. Thus, in the example above, the `value` will be of type `string` implicitly.\n\nIn your specs, you can now use the custom command as expected\n\n*   End-to-End Test\n*   Component Test\n\n```\nit('works', () => {  // from your cypress/e2e/spec.cy.ts  cy.visit('/')  // IntelliSense and TS compiler should  // not complain about unknown method  cy.dataCy('greeting')})\n```\n\n```\nit('works', () => {  // from your src/components/MyComponent.cy.ts  cy.mount(<MyComponent />)  // IntelliSense and TS compiler should  // not complain about unknown method  cy.dataCy('greeting')})\n```\n\n#### Adding child or dual commands\n\nWhen you add a custom command with `prevSubject`, Cypress will infer the subject type automatically based on the specified `prevSubject`.\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      /**       * Custom command to type a few random words into input elements       * @param count=3       * @example cy.get('input').typeRandomWords()       */      typeRandomWords(        count?: number,        options?: Partial<TypeOptions>      ): Chainable<JQuery<HTMLElement>>    }  }}\n```\n\ncypress/support/commands.ts\n\n```\nCypress.Commands.add(  'typeRandomWords',  { prevSubject: 'element' },  (subject /* :JQuery<HTMLElement> */, count = 3, options?) => {    return cy.wrap(subject).type(generateRandomWords(count), options)  })\n```\n\n#### Overwriting child or dual commands\n\nWhen overwriting either built-in or custom commands which make use of `prevSubject`, you must specify generic parameters to help the type-checker to understand the type of the `prevSubject`.\n\ncypress/support/commands.ts\n\n```\ninterface TypeOptions extends Cypress.TypeOptions {  sensitive: boolean}Cypress.Commands.overwrite<'type', 'element'>(  'type',  (originalFn, element, text, options?: Partial<TypeOptions>) => {    if (options && options.sensitive) {      // turn off original log      options.log = false      // create our own log with masked message      Cypress.log({        $el: element,        name: 'type',        message: '*'.repeat(text.length),      })    }    return originalFn(element, text, options)  })\n```\n\nAs you can see there are generic parameters `<'type', 'element'>` are used:\n\n1.  The first parameter is the command name, equal to first parameter passed to `Cypress.Commands.overwrite`.\n2.  The second parameter is the type of the `prevSubject` that is used by the original command. Possible values:\n    *   'element' infers it as `JQuery<HTMLElement>`\n    *   'window' infers it as `Window`\n    *   'document' infers it as `Document`\n    *   'optional' infers it as `unknown`\n\n#### Examples:\n\n*   See [Adding Custom Commands (TS)](https://github.com/cypress-io/cypress-example-recipes#fundamentals) example recipe.\n",
      "section": "app",
      "anchors": [
        "types-for-custom-commands"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 895
    },
    {
      "id": "app/tooling/typescript-support#declare-global-requires-a-typescript-module-file",
      "doc_id": "app/tooling/typescript-support",
      "heading": "declare global requires a TypeScript module file",
      "heading_level": 4,
      "content_markdown": "#### `declare global` requires a TypeScript module file\n\nTypeScript distinguishes between two kinds of files:\n\n*   **Module** — any file with at least one top-level `import` or `export` statement\n*   **Script (ambient)** — a file with no imports or exports\n\n`declare global { ... }` is only valid inside a **module** file. If your `commands.ts` has no imports, TypeScript will raise an error such as: _\"Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.\"_\n\nThe simplest fix is to add `export {}` at the bottom of the file so TypeScript treats it as a module:\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      dataCy(value: string): Chainable<JQuery<HTMLElement>>    }  }}export {} // turns this file into a module so declare global is valid\n```\n\nAlternatively, move your type declarations into a standalone [external typings file](#Using-an-External-Typings-File) where no `import` or `export` is needed.\n\nConversely, if you use `declare namespace Cypress { ... }` **without** the `declare global` wrapper inside a file that _does_ have imports, TypeScript will **not** augment the global `Cypress` namespace — your custom commands will still appear as unknown.\n\nA nice detailed JSDoc comment above the method type will be really appreciated by any users of your custom command.\n\nTypes of all the parameters taken by the implementation callback are inferred automatically based on the declared interface. Thus, in the example above, the `value` will be of type `string` implicitly.\n\nIn your specs, you can now use the custom command as expected\n\n*   End-to-End Test\n*   Component Test\n\n```\nit('works', () => {  // from your cypress/e2e/spec.cy.ts  cy.visit('/')  // IntelliSense and TS compiler should  // not complain about unknown method  cy.dataCy('greeting')})\n```\n\n```\nit('works', () => {  // from your src/components/MyComponent.cy.ts  cy.mount(<MyComponent />)  // IntelliSense and TS compiler should  // not complain about unknown method  cy.dataCy('greeting')})\n```\n",
      "section": "app",
      "anchors": [
        "declare-global-requires-a-typescript-module-file"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 411
    },
    {
      "id": "app/tooling/typescript-support#adding-child-or-dual-commands",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Adding child or dual commands",
      "heading_level": 4,
      "content_markdown": "#### Adding child or dual commands\n\nWhen you add a custom command with `prevSubject`, Cypress will infer the subject type automatically based on the specified `prevSubject`.\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      /**       * Custom command to type a few random words into input elements       * @param count=3       * @example cy.get('input').typeRandomWords()       */      typeRandomWords(        count?: number,        options?: Partial<TypeOptions>      ): Chainable<JQuery<HTMLElement>>    }  }}\n```\n\ncypress/support/commands.ts\n\n```\nCypress.Commands.add(  'typeRandomWords',  { prevSubject: 'element' },  (subject /* :JQuery<HTMLElement> */, count = 3, options?) => {    return cy.wrap(subject).type(generateRandomWords(count), options)  })\n```\n",
      "section": "app",
      "anchors": [
        "adding-child-or-dual-commands"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 120
    },
    {
      "id": "app/tooling/typescript-support#overwriting-child-or-dual-commands",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Overwriting child or dual commands",
      "heading_level": 4,
      "content_markdown": "#### Overwriting child or dual commands\n\nWhen overwriting either built-in or custom commands which make use of `prevSubject`, you must specify generic parameters to help the type-checker to understand the type of the `prevSubject`.\n\ncypress/support/commands.ts\n\n```\ninterface TypeOptions extends Cypress.TypeOptions {  sensitive: boolean}Cypress.Commands.overwrite<'type', 'element'>(  'type',  (originalFn, element, text, options?: Partial<TypeOptions>) => {    if (options && options.sensitive) {      // turn off original log      options.log = false      // create our own log with masked message      Cypress.log({        $el: element,        name: 'type',        message: '*'.repeat(text.length),      })    }    return originalFn(element, text, options)  })\n```\n\nAs you can see there are generic parameters `<'type', 'element'>` are used:\n\n1.  The first parameter is the command name, equal to first parameter passed to `Cypress.Commands.overwrite`.\n2.  The second parameter is the type of the `prevSubject` that is used by the original command. Possible values:\n    *   'element' infers it as `JQuery<HTMLElement>`\n    *   'window' infers it as `Window`\n    *   'document' infers it as `Document`\n    *   'optional' infers it as `unknown`\n",
      "section": "app",
      "anchors": [
        "overwriting-child-or-dual-commands"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 211
    },
    {
      "id": "app/tooling/typescript-support#types-for-custom-queries",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Types for Custom Queries",
      "heading_level": 3,
      "content_markdown": "### Types for Custom Queries\n\nWhen adding [custom queries](/llm/markdown/api/cypress-api/custom-queries.md) with `Cypress.Commands.addQuery()`, you must declare the query on the `Chainable` interface **before** registering it. Cypress infers the query callback's argument types from that declaration.\n\nUnlike custom commands, query callbacks receive `this` as a `Cypress.Command` (not `Mocha.Context`), and the callback must return an inner function that performs the query synchronously.\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      /**       * Gets the currently focused DOM element.       * @example cy.focused2()       */      focused2(        options?: Partial<Cypress.Loggable & Cypress.Timeoutable>      ): Chainable<JQuery>    }    // Required so this.set('timeout', ...) type-checks in query callbacks    interface EnqueuedCommandAttributes {      timeout?: number    }  }}Cypress.Commands.addQuery(  'focused2',  function focused2(    options: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}  ) {    const log =      options.log !== false &&      Cypress.log({        ...(options.timeout !== undefined && { timeout: options.timeout }),      })    this.set('timeout', options.timeout)    return () => {      let $el = cy.getFocused()      // ...      return $el    }  })\n```\n\nWhen passing optional `timeout` to `Cypress.log()`, avoid writing `{ timeout: options.timeout }` directly if `options.timeout` may be `undefined`. With strict TypeScript settings such as `exactOptionalPropertyTypes`, explicitly passing `undefined` is not assignable to an optional property. Use a conditional spread instead, as shown above.\n\nFor queries that accept additional options, combine the relevant Cypress option interfaces with `Partial<>`, matching how built-in queries are typed. For example, a query with timeout and shadow DOM support might use `Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.Shadow>`.\n\nTo overwrite an existing query, declare the query on `Chainable` as usual and use `Cypress.Commands.overwriteQuery()`. The first argument to your callback is the original query function:\n\ncypress/support/commands.ts\n\n```\ndeclare global {  namespace Cypress {    interface Chainable {      get(        selector: string,        options?: Partial<Cypress.Loggable & Cypress.Timeoutable>      ): Chainable<JQuery<HTMLElement>>    }  }}Cypress.Commands.overwriteQuery('get', function (originalFn, ...args) {  return originalFn.apply(this, args)})\n```\n",
      "section": "app",
      "anchors": [
        "types-for-custom-queries"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 381
    },
    {
      "id": "app/tooling/typescript-support#types-for-custom-window-properties",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Types for custom window properties",
      "heading_level": 3,
      "content_markdown": "### Types for custom window properties\n\n[`cy.window()`](/llm/markdown/api/commands/window.md) yields an `AUTWindow` object, which is typed as `Window & typeof globalThis & Cypress.ApplicationWindow`. The `Cypress.ApplicationWindow` interface is an empty extension point that you can augment to tell TypeScript about properties your application adds to `window`.\n\nExtend the interface in your support file or a `*.d.ts` file:\n\ncypress/support/e2e.ts\n\n```\ndeclare global {  namespace Cypress {    interface ApplicationWindow {      // add the properties your app sets on window      env: {        DISABLE: boolean      }    }  }}\n```\n\nTypeScript will now recognize those properties inside `cy.window()` callbacks:\n\n```\ncy.window().then((win) => {  win.env.DISABLE = true // no TypeScript error})\n```\n",
      "section": "app",
      "anchors": [
        "types-for-custom-window-properties"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 137
    },
    {
      "id": "app/tooling/typescript-support#types-for-custom-assertions",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Types for custom assertions",
      "heading_level": 3,
      "content_markdown": "### Types for custom assertions\n\nIf you extend Cypress assertions, you can extend the assertion types to make the TypeScript compiler understand the new methods. See the [Recipe: Adding Chai Assertions](/llm/markdown/app/references/recipes.md#Fundamentals) for instructions.\n",
      "section": "app",
      "anchors": [
        "types-for-custom-assertions"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 44
    },
    {
      "id": "app/tooling/typescript-support#types-for-plugins",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Types for plugins",
      "heading_level": 3,
      "content_markdown": "### Types for plugins\n\nWhen using [`defineConfig`](/llm/markdown/app/references/configuration.md) in your `cypress.config.ts` file, TypeScript types for [`setupNodeEvents`](/llm/markdown/app/references/configuration.md#setupNodeEvents) are inferred automatically — no additional annotation is needed:\n\ncypress.config.ts\n\n```\nimport { defineConfig } from 'cypress'export default defineConfig({  e2e: {    setupNodeEvents(on, config) {      // implement node event listeners here    },  },})\n```\n\nIf you extract your plugin setup into a separate function or file, you can annotate it with the `Cypress.PluginConfig` type:\n\ncypress/plugins/index.ts\n\n```\nconst setupNodeEvents: Cypress.PluginConfig = (on, config) => {  // implement node event listeners here}export default setupNodeEvents\n```\n",
      "section": "app",
      "anchors": [
        "types-for-plugins"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 116
    },
    {
      "id": "app/tooling/typescript-support#using-an-external-typings-file",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Using an External Typings File",
      "heading_level": 3,
      "content_markdown": "### Using an External Typings File\n\nYou might find it easier to organize your types by moving them from the support file into an external [declaration (\\*.d.ts) file](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html). To do so, create a new file, like _cypress.d.ts_, and cut the types for your custom commands/assertions from the _support_ file and into the new file.\n\n#### Ambient declaration file (no imports needed)\n\nA plain `.d.ts` file with no `import` or `export` statements is treated by TypeScript as an _ambient script_. In this context you can declare the namespace **directly** — the `declare global` wrapper is not required:\n\n*   cypress/support/commands.d.ts\n\n```\n// No imports — TypeScript treats this as an ambient declaration file.// Declare the namespace directly (no declare global wrapper needed).declare namespace Cypress {  interface Chainable {    /**     * Custom command to select DOM element by data-cy attribute.     * @example cy.dataCy('greeting')     */    dataCy(value: string): Chainable<JQuery<HTMLElement>>  }}\n```\n\nIf TypeScript does not resolve Cypress types automatically (for example when the `types` field in your `tsconfig.json` does not include `\"cypress\"`), add a triple-slash reference at the top of the declaration file:\n\n```\n/// <reference types=\"cypress\" />\n```\n\n#### File with imports (e.g. `cy.mount`)\n\nWhen the declaration file imports something — such as `cy.mount` for component testing — the `import` turns it into a TypeScript module and `declare global` is required:\n\n*   cypress.d.ts\n\n```\nimport { mount } from 'cypress/react'// Augment the Cypress namespace to include type definitions for// your custom command.// Alternatively, can be defined in cypress/support/component.d.ts// with a <reference path=\"./component\" /> at the top of your spec.declare global {  namespace Cypress {    interface Chainable {      mount: typeof mount    }  }}\n```\n\nYou might need to include the _\\*.d.ts_ in the include options in any _tsconfig.json_ files in your project for TypeScript to pick up the new types:\n\n*   tsconfig.json\n\n```\n\"include\": [  \"src\",  \"./cypress.d.ts\"]\n```\n\n*   ./cypress/tsconfig.json\n\n```\n\"include\": [  \"**/*.ts\",  \"../cypress.d.ts\"]\n```\n\n**TypeScript must be able to find the declaration file**\n\nIf you rename or move a declaration file, verify that its path is covered by the `include` globs in every `tsconfig.json` that needs to see it. A common mistake is placing a `global.d.ts` inside `cypress/support/` while the `cypress/tsconfig.json` only includes `**/*.ts` — `.d.ts` files are matched by `**/*.ts` only if the glob is `**/*.{ts,d.ts}` or simply `**/*`. Safest practice: list the file explicitly or use `\"include\": [\"**/*.ts\", \"**/*.d.ts\"]`.\n",
      "section": "app",
      "anchors": [
        "using-an-external-typings-file"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 517
    },
    {
      "id": "app/tooling/typescript-support#ambient-declaration-file-no-imports-needed",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Ambient declaration file (no imports needed)",
      "heading_level": 4,
      "content_markdown": "#### Ambient declaration file (no imports needed)\n\nA plain `.d.ts` file with no `import` or `export` statements is treated by TypeScript as an _ambient script_. In this context you can declare the namespace **directly** — the `declare global` wrapper is not required:\n\n*   cypress/support/commands.d.ts\n\n```\n// No imports — TypeScript treats this as an ambient declaration file.// Declare the namespace directly (no declare global wrapper needed).declare namespace Cypress {  interface Chainable {    /**     * Custom command to select DOM element by data-cy attribute.     * @example cy.dataCy('greeting')     */    dataCy(value: string): Chainable<JQuery<HTMLElement>>  }}\n```\n\nIf TypeScript does not resolve Cypress types automatically (for example when the `types` field in your `tsconfig.json` does not include `\"cypress\"`), add a triple-slash reference at the top of the declaration file:\n\n```\n/// <reference types=\"cypress\" />\n```\n",
      "section": "app",
      "anchors": [
        "ambient-declaration-file-no-imports-needed"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 173
    },
    {
      "id": "app/tooling/typescript-support#file-with-imports-e-g-cy-mount",
      "doc_id": "app/tooling/typescript-support",
      "heading": "File with imports (e.g. cy.mount)",
      "heading_level": 4,
      "content_markdown": "#### File with imports (e.g. `cy.mount`)\n\nWhen the declaration file imports something — such as `cy.mount` for component testing — the `import` turns it into a TypeScript module and `declare global` is required:\n\n*   cypress.d.ts\n\n```\nimport { mount } from 'cypress/react'// Augment the Cypress namespace to include type definitions for// your custom command.// Alternatively, can be defined in cypress/support/component.d.ts// with a <reference path=\"./component\" /> at the top of your spec.declare global {  namespace Cypress {    interface Chainable {      mount: typeof mount    }  }}\n```\n\nYou might need to include the _\\*.d.ts_ in the include options in any _tsconfig.json_ files in your project for TypeScript to pick up the new types:\n\n*   tsconfig.json\n\n```\n\"include\": [  \"src\",  \"./cypress.d.ts\"]\n```\n\n*   ./cypress/tsconfig.json\n\n```\n\"include\": [  \"**/*.ts\",  \"../cypress.d.ts\"]\n```\n\n**TypeScript must be able to find the declaration file**\n\nIf you rename or move a declaration file, verify that its path is covered by the `include` globs in every `tsconfig.json` that needs to see it. A common mistake is placing a `global.d.ts` inside `cypress/support/` while the `cypress/tsconfig.json` only includes `**/*.ts` — `.d.ts` files are matched by `**/*.ts` only if the glob is `**/*.{ts,d.ts}` or simply `**/*`. Safest practice: list the file explicitly or use `\"include\": [\"**/*.ts\", \"**/*.d.ts\"]`.\n",
      "section": "app",
      "anchors": [
        "file-with-imports-e-g-cy-mount"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 272
    },
    {
      "id": "app/tooling/typescript-support#set-up-your-dev-environment",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Set up your dev environment",
      "heading_level": 3,
      "content_markdown": "### Set up your dev environment\n\nPlease refer to your code editor in [TypeScript's Editor Support doc](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support) and follow the instructions for your IDE to get TypeScript support and [intelligent code completion](/llm/markdown/app/tooling/IDE-integration.md#Intelligent-Code-Completion) configured in your developer environment before continuing. TypeScript support is built in for [Visual Studio Code](https://code.visualstudio.com/), [Visual Studio](https://www.visualstudio.com/), and [WebStorm](https://www.jetbrains.com/webstorm/) - all other editors require extra setup.\n",
      "section": "app",
      "anchors": [
        "set-up-your-dev-environment"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 79
    },
    {
      "id": "app/tooling/typescript-support#clashing-types-with-jest",
      "doc_id": "app/tooling/typescript-support",
      "heading": "Clashing types with Jest",
      "heading_level": 3,
      "content_markdown": "### Clashing types with Jest\n\nIf you are using both Jest and Cypress in the same project, the TypeScript types registered globally by the two test runners can clash. For example, both Jest and Cypress provide the clashing types for the `describe` and `it` functions. Both Jest and Expect (bundled inside Cypress) provide the clashing types for the `expect` assertion, etc.\n\nThe recommended solution is to use **separate `tsconfig.json` files** for your Jest tests and your Cypress tests.\n\n**Step 1:** Create (or ensure you have) a `cypress/tsconfig.json` that explicitly limits types to only what Cypress needs:\n\ncypress/tsconfig.json\n\n```\n{  \"compilerOptions\": {    \"target\": \"es6\",    \"lib\": [\"es6\", \"dom\"],    \"sourceMap\": true,    \"types\": [\"cypress\", \"node\"]  },  \"include\": [\"**/*.ts\"]}\n```\n\n**Step 2:** Exclude the `cypress` folder (and `cypress.config.ts`) from your root `tsconfig.json` so that Jest does not pick up Cypress global types:\n\ntsconfig.json\n\n```\n{  \"exclude\": [\"cypress.config.ts\", \"cypress\", \"node_modules\"]}\n```\n\nWith this setup, Jest uses the root `tsconfig.json` (without Cypress types) and Cypress uses its own `cypress/tsconfig.json` (with Cypress types), so the two sets of globals no longer interfere with each other.\n",
      "section": "app",
      "anchors": [
        "clashing-types-with-jest"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 236
    },
    {
      "id": "app/tooling/typescript-support#history",
      "doc_id": "app/tooling/typescript-support",
      "heading": "History",
      "heading_level": 2,
      "content_markdown": "## History\n\n| Version | Changes |\n| --- | --- |\n| [15.19.0](/llm/markdown/app/references/changelog.md#15-19-0) | Added support for TypeScript 7.0 |\n| [15.14.0](/llm/markdown/app/references/changelog.md#15-14-0) | Added support for TypeScript 6.0 |\n| [15.0.0](/llm/markdown/app/references/changelog.md#15-0-0) | Raised minimum required TypeScript version from 4.0+ to 5.0+ and replaced `ts-node` with `tsx` to parse and run the `cypress.config.ts` file. |\n| [13.0.0](/llm/markdown/app/references/changelog.md#13-0-0) | Raised minimum required TypeScript version from 3.4+ to 4.0+ |\n| [10.0.0](/llm/markdown/app/references/changelog.md#10-0-0) | Update guide to cover TypeScript setup for component testing |\n| [5.0.0](/llm/markdown/app/references/changelog.md#5-0-0) | Raised minimum required TypeScript version from 2.9+ to 3.4+ |\n| [4.4.0](/llm/markdown/app/references/changelog.md#4-4-0) | Added support for TypeScript without needing your own transpilation through preprocessors. |\n",
      "section": "app",
      "anchors": [
        "history"
      ],
      "path": "/llm/json/chunked/app/tooling/typescript-support.json",
      "token_estimate": 145
    }
  ]
}