-
Notifications
You must be signed in to change notification settings - Fork 668
fix: revert default element typings to HTMLElement
#1885
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
Conversation
The type definitions were updated to allow generic element typing in vuejs#1871 However, this "loosened" the default type from `HTMLElement` to `Element. This was actually a breaking change. For example, consumers may have had this test code: ```ts wrapper.element.click() ``` But `click()` only exists on `HTMLElement`, not on `Element`, so test compilation fails. This change moves the default type back to `HTMLElement`. If we want to loosen this requirement in the future, it should be considered a breaking change.
8de6ebe
to
d34b00b
Compare
Ah, I see. That said, you can find things other than HTMLElement with Maybe we should revert, then release the "loosened" types as a minor (so 1.3, in this case). Regarding your example, is What do you think? I do agree this kind of change is a bit inconvenient, and should not have been a patch release. Even if we revert, you will have this problem when you update to the next minor release (1.3 - we cannot do a 2.x, that's already used for Vue 3). |
@lmiller1990 The other thing to do to not make this breaking is to just keep That being said, I can understand if this is what you want to do to be more "correct". Just a bit surprising on a patch version in particular. As a side-note, even Microsoft's official type definitions seem to be a little bit confused on the matter of casting verbosity vs spec compliance: microsoft/TypeScript#4689 |
@alecgibson seems VTU v2 (for Vue 3) is using I agree doing this as a patch release was a bad idea, it should definitely have been a minor release. I'm not sure there's value in reverting it, only to re-release it as a minor in the near future. For |
Yes definitely a shame; this will definitely make the TS syntax for this library pretty verbose — (lots of |
Hang on - why can't we just rework this PR to use the similar types from VTU v2? It can actually infer the element type, eg: mount({}).find('div').element.click() What do you think? It won't work with |
Yes it's fine if you reference by element tag, but I personally tend to avoid that to keep tests from being too fragile (and often looking things up by just eg The scope of this PR was just to make the change un-breaking; so if you want to adopt the v3 types, that should probably be a different change. |
I understand now. Fair enough - I agree that this should not have been a patch, definitely not ideal. Happy to discuss more on general type improvements, the Vue 3 lib is a good place to look for ideas since we also have a |
As a side-note, it sounds like using this sort of generic typing where the type isn't used in the parameter list is an anti-pattern, and I guess now I think about it, I don't really understand the value of doing this over just forcing consumers to cast: const button = wrapper.find('.button') as HTMLButtonElement; |
Hm, I don't fully understand "Type parameters that aren't used in the parameter list are an anti-pattern". Why is this an anti pattern? Does this mean we should just not have any generic here at all? I could be misunderstand this. If we have made a bad decision with this type, we can change it. We should have a good reason as to why, and make sure V2 also has the same types, or it'll be hard to upgrade. I think the difference between casting with |
I think it's an anti-pattern, because a purist would argue that this use of generics offers no "real" type safety. For example, a classic example of a generic might be the const arr = new Array<number>();
arr.push(1);
const item: number = arr.pop(); The generic here offers type-safety, because it ties everything about the class together: you definitely can only add a If the const arr = new Array(); // Defaults to any
arr.push<number>(1);
const item = arr.pop<string>(); ...then you've not gained anything from the type system, and you're just abusing the fact that the methods let you override the expected type — essentially you've just cast the result — which then begs the question of what value is the type system adding here. If we follow our function foo<T extends any = any>(): T {}
const bar = foo<string>(); ...which really offers no more type safety than this: function foo(): any {}
const bar = foo() as string;
That is not the case: However, all that being said, as a pragmatist, I do think if we're going to be forced to constantly cast our wrapper.find<HTMLElement>('.foo').element.click() is arguably "nicer" than this syntax: (wrapper.find('.foo').element as HTMLElement).click()
// Or alternatively...
(<HTMLElement> wrapper.find('.foo').element).click() |
The type definitions were updated to allow generic element typing in
#1871
However, this "loosened" the default type from
HTMLElement
to`Element. This was actually a breaking change.
For example, consumers may have had this test code:
But
click()
only exists onHTMLElement
, not onElement
, so testcompilation fails.
This change moves the default type back to
HTMLElement
. If we want toloosen this requirement in the future, it should be considered a
breaking change.
What kind of change does this PR introduce? (check at least one)
Does this PR introduce a breaking change? (check one)
If yes, please describe the impact and migration path for existing applications:
The PR fulfills these requirements:
dev
branch.fix #xxx[,#xxx]
, where "xxx" is the issue number)If adding a new feature, the PR's description includes:
Other information: