From b403efef297d8cf9f70da4d0d002759cd292b011 Mon Sep 17 00:00:00 2001 From: Alex Schwartz Date: Tue, 22 Jul 2025 15:12:03 -0400 Subject: [PATCH 1/7] feat: make ability for cy.task to be type-safe --- cli/types/cypress.d.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 65f51f96722e..8fc2d9317a48 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -3,6 +3,20 @@ /// /// +type IsAny = + (() => T extends X ? 1 : 2) extends + (() => T extends any ? 1 : 2) ? true : false; + +type CypressConfig_Data = typeof import('../../../cypress.config') +type AllTasks_CJS = CypressConfig_Data['CypressTasks'] +type AllTasks_ESM = CypressConfig_Data['default']['CypressTasks'] + +type AllTasks = IsAny extends true ? AllTasks_ESM : AllTasks_CJS +type TaskEventNames = keyof AllTasks & string + +type MyParameter = Parameters[0] +type MyReturnType = Awaited> + declare namespace Cypress { type FileContents = string | any[] | object type HistoryDirection = 'back' | 'forward' @@ -2164,7 +2178,23 @@ declare namespace Cypress { * * @see https://on.cypress.io/api/task */ - task(event: string, arg?: any, options?: Partial): Chainable + task( + event: T, + ...myArgs: IsAny extends true ? + [ + arg?: any, + options?: Partial + ] : Parameters['length'] extends 0 ? + [ + arg?: undefined, + options?: Partial + ] : [ + arg: MyParameter, + options?: Partial + ] + ): Chainable< + IsAny extends true ? unknown : MyReturnType + > /** * Enables you to work with the subject yielded from the previous command. From 2ecdda114ab0d245da19e992315d3351cb1a56fc Mon Sep 17 00:00:00 2001 From: Alex Schwartz Date: Tue, 22 Jul 2025 15:15:58 -0400 Subject: [PATCH 2/7] Update CHANGELOG.md --- cli/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 30c4de1ead4b..b0f8fef5b084 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -3,6 +3,10 @@ _Released 7/30/2025 (PENDING)_ +**Features:** + +- Adds ability for cy.task function to have type-safety [#32075](https://github.com/cypress-io/cypress/pull/32075). + **Bugfixes:** - Fixed missing support for setting an absolute path for `component.indexHtmlFile` in `@cypress/webpack-dev-server`. Fixes [#31819](https://github.com/cypress-io/cypress/issues/31819). From e14ba4fb4f3ed94c15f49a8317fae7ed1e318339 Mon Sep 17 00:00:00 2001 From: Alex Schwartz Date: Tue, 22 Jul 2025 20:21:38 -0400 Subject: [PATCH 3/7] refactor --- cli/types/cypress.d.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 8fc2d9317a48..fa87e9c9c410 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -3,19 +3,17 @@ /// /// -type IsAny = - (() => T extends X ? 1 : 2) extends - (() => T extends any ? 1 : 2) ? true : false; +type IsAny = object extends T ? true : false; -type CypressConfig_Data = typeof import('../../../cypress.config') -type AllTasks_CJS = CypressConfig_Data['CypressTasks'] -type AllTasks_ESM = CypressConfig_Data['default']['CypressTasks'] +type CypressConfig_Data = typeof import('../../../cypress.config'); +type AllTasks_CJS = CypressConfig_Data['CypressTasks']; +type AllTasks_ESM = CypressConfig_Data['default']['CypressTasks']; -type AllTasks = IsAny extends true ? AllTasks_ESM : AllTasks_CJS -type TaskEventNames = keyof AllTasks & string +type AllTasks = IsAny extends true ? AllTasks_ESM : AllTasks_CJS; +type TaskEventNames = keyof AllTasks & string; -type MyParameter = Parameters[0] -type MyReturnType = Awaited> +type MyParameter = Parameters[0]; +type MyReturnType = Awaited>; declare namespace Cypress { type FileContents = string | any[] | object From 9536f8cd5ae0b574a8b06098b466dac545ba389b Mon Sep 17 00:00:00 2001 From: Alex Schwartz Date: Tue, 22 Jul 2025 20:25:33 -0400 Subject: [PATCH 4/7] partial revert --- cli/types/cypress.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index fa87e9c9c410..699d59575443 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -3,7 +3,9 @@ /// /// -type IsAny = object extends T ? true : false; +type IsAny = + (() => T extends X ? 1 : 2) extends + (() => 1) ? true : false; type CypressConfig_Data = typeof import('../../../cypress.config'); type AllTasks_CJS = CypressConfig_Data['CypressTasks']; From c917c3bfb1b895af77d7da3959fcb65e96cdad40 Mon Sep 17 00:00:00 2001 From: Alex Schwartz Date: Tue, 22 Jul 2025 20:26:37 -0400 Subject: [PATCH 5/7] one last thing --- cli/types/cypress.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 699d59575443..623a198c3df5 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -5,7 +5,7 @@ type IsAny = (() => T extends X ? 1 : 2) extends - (() => 1) ? true : false; + (() => 1) ? true : false; type CypressConfig_Data = typeof import('../../../cypress.config'); type AllTasks_CJS = CypressConfig_Data['CypressTasks']; From 3784b4c48687744798845b9a3e2102bcd62ec075 Mon Sep 17 00:00:00 2001 From: Alex Schwartz Date: Wed, 23 Jul 2025 10:18:45 -0400 Subject: [PATCH 6/7] Update cypress.d.ts --- cli/types/cypress.d.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 623a198c3df5..ad26357028fd 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -3,15 +3,13 @@ /// /// -type IsAny = - (() => T extends X ? 1 : 2) extends - (() => 1) ? true : false; +type HasNoType = unknown extends T ? true : false; type CypressConfig_Data = typeof import('../../../cypress.config'); type AllTasks_CJS = CypressConfig_Data['CypressTasks']; type AllTasks_ESM = CypressConfig_Data['default']['CypressTasks']; -type AllTasks = IsAny extends true ? AllTasks_ESM : AllTasks_CJS; +type AllTasks = HasNoType extends true ? AllTasks_ESM : AllTasks_CJS; type TaskEventNames = keyof AllTasks & string; type MyParameter = Parameters[0]; @@ -2180,7 +2178,7 @@ declare namespace Cypress { */ task( event: T, - ...myArgs: IsAny extends true ? + ...myArgs: HasNoType extends true ? [ arg?: any, options?: Partial @@ -2193,7 +2191,7 @@ declare namespace Cypress { options?: Partial ] ): Chainable< - IsAny extends true ? unknown : MyReturnType + HasNoType extends true ? unknown : MyReturnType > /** From 701c2be06b4734d888c8d52a25d4f7c92e677a12 Mon Sep 17 00:00:00 2001 From: Alex Schwartz Date: Wed, 23 Jul 2025 10:24:50 -0400 Subject: [PATCH 7/7] Update cypress.d.ts --- cli/types/cypress.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index ad26357028fd..184a0c431958 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -3,7 +3,9 @@ /// /// -type HasNoType = unknown extends T ? true : false; +type HasNoType = + (() => T extends X ? 1 : 2) extends + (() => 1) ? true : false; type CypressConfig_Data = typeof import('../../../cypress.config'); type AllTasks_CJS = CypressConfig_Data['CypressTasks'];