Skip to content

instanceof with child elements of iframe documents. #21568

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

Closed
jahorton opened this issue Feb 2, 2018 · 2 comments
Closed

instanceof with child elements of iframe documents. #21568

jahorton opened this issue Feb 2, 2018 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@jahorton
Copy link

jahorton commented Feb 2, 2018

I'm not entirely sure whether this one should be called a suggestion or a bug, due to the interactions it involves and how that might be related to TypeScript's design. Tested with 2.6.2 and 2.7.1.

Our problem can best be explained by examining the following two blocks of code first:

Code Set 1

var frame = document.getElementById('myFrame') as HTMLIFrameElement
var ele = frame.contentDocument.getElementById('input1') as HTMLInputElement;
// ...
if(ele instanceof HTMLInputElement) {
  console.log('Yep, it\'s an HTMLInputElement.');
} else {
  console.log('HTMLInputElement constructor mismatch!')
}

Expected behavior:

Console log:
> Yep, it's an HTMLInputElement.

Actual behavior:
> HTMLInputElement constructor mismatch!

The short version - any element within an HTMLIFrameElement's internal document is based upon a different constructor set, as the HTMLIFrameElement has its own Window instance (.contentWindow). In the general case, this is good JavaScript design that helps to isolate documents within an HTMLIFrameElement from the master document.

Code Set 2

var ele = document.getElementById('input1') as HTMLInputElement
// ...
var proto = window.HTMLInputElement  // Error is on this line.
if(ele instanceof proto) {
  console.log('Yep, it\'s an HTMLInputElement.');
}

Expected behavior:

Console log:
> Yep, it's an HTMLInputElement.

Actual behavior:

source.ts(__, __): error TS2339: Property 'HTMLInputElement' does not exist on type 'Window'

Never mind the fact that it actually does exist there in JavaScript on all the major browsers; TypeScript doesn't acknowledge that the base window object (or .defaultView/.contentWindow property Window object) contains the original class constructors for its corresponding Document.

Overall desired behavior:

At present, the above two issues combine to make the following impossible in plain TypeScript without losing type information to some degree:

var frame = document.getElementById('myFrame') as HTMLIFrameElement
var ele: HTMLElement = frame.contentDocument.getElementById('input1');

if(ele instanceof ele.ownerDocument.defaultView.HTMLInputElement) {
  console.log("We have an instance of the IFrame's HTMLInputElement class!");
  console.log("It's value: " + ele.value);
}

Even if, within our own codebase, we extend Window via interface to have a property HTMLInputElement: () => HTMLInputElement to model the constructor all Window instances possess, ele.value's line will return an error because it will require a manual cast, unlike with a plain ele instanceof HTMLInputElement... which fails here because HTMLInputElement will correspond to the constructor from the base window: Window. There's no way to do this at present that feels like 'proper' TypeScript.

The ideal scenario would thus be for the Window class to contain a readonly set of HTMLElement constructors (among others), which should allow for safe use of instanceof upon window.HTMLElement equivalent with that of upon top-level HTMLElement.


Search Terms:
iframe
instanceof
cross-frame
window
constructor

@mhegazy
Copy link
Contributor

mhegazy commented Feb 2, 2018

Never mind the fact that it actually does exist there in JavaScript on all the major browsers; TypeScript doesn't acknowledge that the base window object (or .defaultView/.contentWindow property Window object) contains the original class constructors for its corresponding Document.

Global declarations are intentionally elided from Window. you can always add them in your own code base by adding;

interface Window {
    HTMLInputElement : typeof HTMLInputElement ;
}

See #19816 for more details.

@mhegazy mhegazy added the Duplicate An existing issue was already created label Feb 2, 2018
@jahorton
Copy link
Author

jahorton commented Feb 2, 2018

Thanks.

@jahorton jahorton closed this as completed Feb 2, 2018
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

2 participants