Skip to content

Makes the ontouch* events on window optional. #749

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

Merged
merged 1 commit into from
Nov 14, 2019

Conversation

MicahZoltu
Copy link
Contributor

Browsers without touch support (e.g., Firefox/Chrome on desktop) will not have ontouch* events defined on window, so the current type definition is not correct.

@MicahZoltu
Copy link
Contributor Author

MicahZoltu commented Aug 31, 2019

Fixes microsoft/TypeScript#33176

@orta
Copy link
Contributor

orta commented Sep 11, 2019

This makes sense, want to update the snapshots and this can be merged?

@MicahZoltu
Copy link
Contributor Author

How does one "update the snapshots"? Is that a fancy way of saying "rebase on master"?

@MicahZoltu
Copy link
Contributor Author

Ah, you are probably referring to the instructions here? https://github.com/microsoft/TSJS-lib-generator#contribution-guidelines

It makes me sad that those aren't done automatically as part of CI/CD. 😢 It means I'll have to actually clone this project to make this PR rather than just doing it in the GitHub UI.

@MicahZoltu
Copy link
Contributor Author

Hmm, digging in on this it seems I need to add an overridingTypes.json entry, presumably on the window interface. Is there a way to say, "keep the auto-generated signature, but make it optional" or do I have to provide a copy of the signature with | undefined on it?

@MicahZoltu
Copy link
Contributor Author

I have rebased the PR and applied the necessary change to overridingTypes.json in what I think is the proper way. I couldn't figure out how to make something optional other than by adding | undefined to the type signature. It is also worth noting that the global variable ontouchcancel will not be defined (different from undefined because JavaScript), yet the TS definition currently has it as declare var ontouchcancel: ... | null | undefined, which means if you do if (ontouchstart === undefined) TS will compile but you'll get a runtime exception I believe. I don't know how to resolve this.

@@ -129,6 +129,18 @@
"property": {
"onerror": {
"override-type": "OnErrorEventHandler"
},
"ontouchcancel": {
"override-type": "((this: Window, ev: TouchEvent) => any) | null | undefined"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try replacing this line with nullable: 1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, why didn't I think that nullable: 1 would change a nullable type into a nullable | undefined type...

@MicahZoltu
Copy link
Contributor Author

Rebased again and updated to use "nullable": 1 instead of the manual override.

@saschanaz
Copy link
Contributor

You also need to run npm run build && npm run baseline-accept 😁

@MicahZoltu
Copy link
Contributor Author

Bleck. I cannot run npm baseline-accept because it doesn't work on Windows. 😢 If a maintainer wants to run that, feel free. Or just crib this PR and make a new one. I just want the code fixed, don't care how it happens.

@MicahZoltu
Copy link
Contributor Author

Ah, easy enough to replicate the baseline-accept step by hand. Fixed.

@saschanaz
Copy link
Contributor

Could you try npm i cpx2 and run it again? Because I accidentally broke it 🙄

@MicahZoltu
Copy link
Contributor Author

npm install cpx2 does appear to resolve the error. I already have matching baseline, so I'm just going to assume the copy did something. 😉

@saschanaz
Copy link
Contributor

saschanaz commented Sep 27, 2019

This PR now unexpectedly is no-op 🤯

I think what we want to do here is marking it as ontouchstart?: (whatever). We should probably create a new way to do it because AFAIK there is no way to do it now.

@@ -129,6 +129,18 @@
"property": {
"onerror": {
"override-type": "OnErrorEventHandler"
},
"ontouchcancel": {
"nullable": 1
Copy link
Contributor

@saschanaz saschanaz Sep 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got an ugly working hack: Try replacing this line with "name": "ontouchcancel?" and so on. This hack is currently being used for nonce?.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I could have sworn that it was not a no-op when I committed...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ewe.... that is dirty... but it appears to work. Pushed.

declare var ontouchend: ((this: Window, ev: TouchEvent) => any) | null;
declare var ontouchmove: ((this: Window, ev: TouchEvent) => any) | null;
declare var ontouchstart: ((this: Window, ev: TouchEvent) => any) | null;
declare var ontouchcancel?: ((this: Window, ev: TouchEvent) => any) | null;
Copy link
Contributor

@saschanaz saschanaz Sep 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, no, this won't work.... Sorry to make you break code 🙄
It seems we need to modify emitter to support this properly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I let this PR lapse until such work is complete, or return to the original solution that will break if the auto-generated types ever change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I got a working way. Please fix src/emitter.ts line 620 as:

-            const requiredModifier = p.required === undefined || p.required === 1 ? "" : "?";
+            const requiredModifier = p.required === undefined || p.required === 1 || prefix ? "" : "?";

And use required: 0 on overridingTypes.json. I tried it and it works this time!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That change doesn't appear to update the global variables:

declare var ontouchcancel: ((this: Window, ev: TouchEvent) => any) | null;
declare var ontouchend: ((this: Window, ev: TouchEvent) => any) | null;
declare var ontouchmove: ((this: Window, ev: TouchEvent) => any) | null;
declare var ontouchstart: ((this: Window, ev: TouchEvent) => any) | null;

Those need to be |undefined as well I believe?
in Firefox if you do >> ontouchcancel you get

ReferenceError: ontouchcancel is not defined

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated PR with your suggested changes in case that is desired behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you're right. We can modify it further:

             }
-            const requiredModifier = p.required === undefined || p.required === 1 ? "" : "?";
+            const required = p.required === undefined || p.required === 1;
+            const requiredModifier = required || prefix ? "" : "?";
             pType = p.nullable ? makeNullable(pType) : pType;
+            if (!required && prefix) {
+                pType += " | undefined"
+            }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. I look forward to the day when someone git-blames me for this and I have no idea what any of it does. 😛

Browsers without touch support (e.g., Firefox/Chrome on desktop) will not have `ontouch*` events defined on `window`, so the current type definition is not correct.

package-lock was out of date and auto-updated on `npm install`.  I can roll that back if desired.
@sandersn
Copy link
Member

sandersn commented Oct 2, 2019

Do we still need this PR if feature detection code like (('ontouchstart' in window) || (window.navigator)) works in 3.6 and later?

@MicahZoltu
Copy link
Contributor Author

I'm not familiar with the feature detection code you are referring to, but the current definition of Window in dom TypeScript lib is incorrect. So unless the feature detection thing you are referring to fixes the bug in the Window definition, this PR is still necessary.

@saschanaz
Copy link
Contributor

I'm not sure the current types can break things given that the in type guard problem is now fixed.

if (window.ontouchstart === undefined) {
    window.ontouchstart // currently this becomes never
}

This is the only weird thing I could find now but it shouldn't break anything.

@MicahZoltu
Copy link
Contributor Author

MicahZoltu commented Oct 2, 2019

The current problem is that window.ontouchstart type definition isn't a union with undefined. This means that the following code will not give a compile time error, but it should:

declare const myWindow: Window
myWindow.ontouchstart(...) // should error at compile time with calling possibly undefined

@saschanaz
Copy link
Contributor

This means that the following code will not give a compile time error

It will, because it's a union with null and null is not callable.

@MicahZoltu
Copy link
Contributor Author

Ah, good point. However, in a desktop browser with no touch interface, window.ontouchcancel is undefined, not null. In TypeScript 3.7.0-beta, the following will compile (just tested) but I believe it will fail at runtime since myWindow.ontouchcancel is undefined, not null:

declare const touchEvent: TouchEvent
declare const myWindow: Window
if (myWindow.ontouchcancel !== null) {
	myWindow.ontouchcancel(touchEvent)
}

@saschanaz
Copy link
Contributor

Hmmm technically yes... but why would anyone directly call a event listener?

@MicahZoltu
Copy link
Contributor Author

🤷‍♂
Regardless of whether it is useful, I think that it should be correct.

@sandersn
Copy link
Member

Seem reasonable to make it correct. If there are unforeseen problems that people run into, we have enough time to revert this change before 3.8.

@sandersn sandersn merged commit e1811c5 into microsoft:master Nov 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants