-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: improve pkg/driver types #21197
Conversation
Thanks for taking the time to open a PR!
|
// mixin lodash methods | ||
_.each(['pick'], (method) => { | ||
return $Command.prototype[method] = function (...args) { | ||
args.unshift(this.attributes) | ||
|
||
return _[method].apply(_, args) | ||
} | ||
}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is added 5 years ago and no other lodash function is added to $Command
. I guess it wouldn't later. So, I moved it inside the class for type.
@@ -0,0 +1,35 @@ | |||
/// <reference path="../../types/cy/commands/session.d.ts" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New file is created because
- types defined in
.ts
cannot be imported tod.ts
files without breakingd.ts
's auto import feature. d.ts
files automatically changed undefined or misspelled types toany
.
@sainthkh Thanks for the updates! |
@@ -347,6 +349,8 @@ export const create = (Cypress, cy) => { | |||
if (_.isFunction(onRetry)) { | |||
return cy.retry(onRetry, options) | |||
} | |||
|
|||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this trailing empty return? It looks very unusual to my eyes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's because TypeScript wants all return paths.
As the type of cy.retry
became specific, TypeScript learned that this function returns a Promise
above but nothing at the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this it's an error.
pick (...args) { | ||
args.unshift(this.attributes) | ||
|
||
return _.pick.apply(_, args as [Record<string, any>, any[]]) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't necessarily think we need to be added this to every command instance. Why can't we use a static method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used in the line below:
cypress/packages/driver/src/cypress/log.ts
Line 125 in 331e541
_.defaults(obj, current != null ? current.pick('name', 'type') : undefined) |
And because of the this
in the this.attributes
. You cannot use non-static
fields with this
inside static
functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sainthkh Can you share the long-term intended type changes? I'm having a hard time understanding the end-goal for the driver package.
It seems like our types patterns are getting inconsistent where some components are exporting their types from their file where other types are being managed in a standalone file, while other types are overriding the CLI types within ./driver/types
AFAIK, there is no rule or documentation about where and how we should define our types. But as a person who wrote a lot of type definitions for Cypress, here are my rules and goals:
The reasons are below. It's a bit long because it's related with the history of Cypress code base. Why are we using TypeScript?Maybe, we should start with the benefit of TypeScript over plain JavaScript. I think there are 2 benefits:
The goal of these type PRs is related with the second reason, making Cypress driver code easier to navigate. Without types, when a developer wants to know where the definition of some functions are, they have to search the entire project and read all the result. With types, they can save much time by just clicking the name.
|
// perf loop | |
for (let cmd of builtInCommands) { | |
// support "export default" syntax | |
cmd = cmd.default || cmd | |
cmd(Commands, Cypress, cy, state, config) | |
} |
When removing type todos in #20601, I thought about moving command options to driver
and adding them to the cli/type
on the build. But it would make the problem more complicated because public and internal interfaces are mixed in the project. So, I decided not to do that and imported types from cli/types
when it's public.
And removing it is a bit hard, because there are some APIs we need to hide from our definition. For example of #20556, $Cy
uses eventemitter2
internally, but it should not expose waitFor
because it can confuse users.
driver/types
The next type file created is driver/types
. It is created mainly to avoid type problems in driver
when we're moving JavaScript to TypeScript.
But there are some limitation of this file because:
- type check isn't stronger than plain
.ts
files. For example, there is currentlyActiveSessionsSessionData
ininternal-types.d.ts
. But this type doesn't exist. It should beCypress.Commands.Session.ActiveSessions
. But TypeScript doesn't alarm because non-existent types areany
ind.ts
files. - It doesn't help navigating files. When you want to learn more about something, it doesn't lead to the real definition, but the
d.ts
. It's not what we wanted.
So, whenever possible, I try to define types inside the .ts
files, and use import
or import type
directly from the defined .ts
file to help navigate.
But removing these d.ts
files isn't the goal, because they are sometimes necessary when we're extending the given types like Window
in types/window.d.ts
in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you for your contribution and the in-depth explanation in the comments 🙂
User facing changelog
N/A. It's adding types for internal use.
Additional details
any
s and make code easier to navigate.How has the user experience changed?
N/A
PR Tasks
cypress-documentation
?type definitions
?cypress.schema.json
?