-
Notifications
You must be signed in to change notification settings - Fork 441
cloneNode Return Type Must Be Active Class, Not Base Class (Node) #1723
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
base: main
Are you sure you want to change the base?
cloneNode Return Type Must Be Active Class, Not Base Class (Node) #1723
Conversation
The `cloneNode` return type is incorrect. The type before this change indicated that `cloneNode` returned a `Node`, which then broke any class that extended `Node`. In reality, `cloneNode` will return an instance of whatever the current class type is, a.k.a. `this` (`DocumentFragment#cloneNode` returns a `DocumentFragment`, not a `Node`).
Thanks for the PR! This section of the codebase is owned by @saschanaz - if they write a comment saying "LGTM" then it will be merged. |
This comment has been minimized.
This comment has been minimized.
Have you read and fixed the issues from this item? |
@HolgerJeromin, I will test that later today. But that issue should be fixed as we aren't manually overriding each subclass'es |
Manual overridding was a workaround to reduce performance problem: #220 (comment) |
Ah, my mistake, @saschanaz. I missed that. If there's no possible workaround that is both performant and covariant, what is the project's focus, performance or accuracy? Making the change to |
You can run |
@saschanaz I took 50 samples before and after the change and averaged each sample set. Results
So it looks like an average total increase of 4 milliseconds on my system. MethodologyThe results were aggregated with some PowerShell. I ran the following script under the main branch, and then I changed Write-Output "Files,Lines,Identifiers,Symbols,Types,Instantiations,Memory used,I/O read,I/O write,Parse time,Bind time,Check time,Emit time,Total time" | Out-File -FilePath ..\before.csv; 1..50 | ForEach-Object { (npx tsc --diagnostics --lib es5 baselines/dom.generated.d.ts | ForEach-Object { ($_ -Split ':')[1].Trim() -ireplace '(s|k)' }) -Split "`n" -Join "," | Out-File -Append -FilePath ..\before.csv } |
@HolgerJeromin I did a little reproduction, and it looks like // Same type parameter as Tablesorter.
interface A<T = HTMLElement> {
x?: T;
}
type An<T = HTMLElement> = A<T>;
type ANode = A<Node>;
type AnElement = An<Element>;
type AnHTMLElement = An;
type AnHTMLAnchorElement = An<HTMLAnchorElement>;
let node: ANode = {};
let element: AnElement = {};
let htmlElement: AnHTMLElement = {};
let htmlAnchorElement: AnHTMLAnchorElement = {};
// All of the return types are correct!
let clonedNode: Node = node.x?.cloneNode()!;
let clonedElement: Element = element.x?.cloneNode()!;
let clonedHtmlElement: HTMLElement = htmlElement.x?.cloneNode()!;
let clonedHtmlAnchorElement: HTMLAnchorElement = htmlAnchorElement.x?.cloneNode()!;
htmlElement = htmlAnchorElement; // Covariance works! 👍🏻
htmlElement = element; // Contravariance doesn't work (as expected). |
@saschanaz Just wanted to follow up with a ping. This was my conclusion:
A 4 millisecond difference seems much more acceptable than the previous 700 millisecond difference. If you have any other concerns please let me know. |
I'm very happy to see work done on this and since it looks like perf impact is minimal, hope this will get merged soon. This would be a huge improvement for front end devs using typescript. |
The
cloneNode
return type is incorrect as per #283, #302, microsoft/TypeScript#17818 and #1578. The type before this PR indicated thatcloneNode
returned aNode
, which then broke any class that extendedNode
. In reality,cloneNode
will return an instance of whatever the current class type is, a.k.a.this
(DocumentFragment#cloneNode
returns aDocumentFragment
, not aNode
).This PR solves this issue by changing the return type of
Node#cloneNode
tothis
.