userEvent.type always returns a promise, but we only need to await it if we're using the { delay: number } as the third argument, according to the docs
// this returns a Promise, although it is not used
userEvent.type(getByRole('button'))
In js that's fine, but in TS, the compiler or eslint might warn you about having floating promises.
that could force the TS users to always use await even though it might not be necessary - it's different from js where we could just not await it.
A possible solution could be to use type overloading when defining the function type, so it returns Promise<void> if { delay: number } is passed, but no value is provided, return void
I think that could be achieved with the following code
type TypeWithoutDelay = (element: TargetElement, text: string, userOpts?: Omit<ITypeOpts, 'delay'> ) => void
type TypeWithDelay = (element: TargetElement, text: string, userOpts: Omit<ITypeOpts, 'delay'> & { delay: number }) => Promise<void>
// then on userEvent.type
declare const userEvent: {
//...
type: TypeWithDelay & TypeWithoutDelay
//...
}
That should allow the inference to work
skipping options

not passing delay


using delay: number (which gives us the Promise as expected)


While this works, I wanted to read your thoughts as the code _does_ return a Promise (instead of void), just that it is not required to be awaited, so it could be misleading, or perhaps it's not worth the effort. I could do the PR as it is just as simple as updating the typings with that option.
Could be a bit simpler I think:
https://www.typescriptlang.org/play?#code/AQKA9GwCIKYGYEsB2CAuCD2SDOwBGAngFzADqArsABICGG6NSwAPABaqoAO2REA5mlbk8AOgDGGALZgA7u2wBrAgD4QMAB6cMAJ1TBkqGNrg0xMYAEkAKgU4wA8p1S4A3iGDBFCTgGEANghiCgD8JHgYGH4wjO6eCt4AguSoGP4Y2DCh+BFRMR4AJjB+NARZSOSSeEaxyGgINH4AykUwYuhYjag0umUVVdo1KAxNLW2YSACiSPm9ldUAviBqmjp6BkYmZpZWNHgAqhnaju04wG4e2KwIcKhZ4ZHRSLFwGGLk2FbaNJxZUK8VMCQegAPsAJlFJIDUCBFsstLpgKhbOYdto+DBUOCYJCgcAALxgiFQ4Cg0jIfIYGRLDTwvRIuzAABiCCi2ASaIBuIJzKiJKZLJgAG0ALrUlYI+nmPacPwYGj5CxDdl8Tl6AnnYBiAJBRVoLIAWQw7xgEwAblDddCPGJWIx0ZasmaoTCxbT9ECNqZzBZ-IEFMdxq5Yl5OFQMObtHcco9Ylq-T4jUDZv0XSBClruuYJDg9MbtE6gSQNVrotoSAAKFo41AkVHozFEoEASnxymApowCHyse1CgrsQ8Vahte69ax1YANAP3XqSIbjQXUJapx4PBgnIGsj7ewGsNgV8AW3i2x2u7F8ng-L6gv3V8Ah4XgHWMeOoQePLVbnOjRlF8vp+uJzYFu17+hue4HkeJ6dt2FyjKgu44Leq4PjWT6ji+jaoO+7YNOQMA8J4qDaMgfB8tgxGkSKfJUFY+oADKvrioK0QxTGoCKOGfgaP4muaQL-h4UHtjB54EfBiGEeW06oSOaKYdib7TqaeEESQFEkUgZGghpVHCjRdGMVhBlsVhnHTtx34LvxS5DJBrYiWeHjkDKcr5Mhg5YXJY5YThiCsiQPIEcqqpcUMWTSrK8qWiFk6xMJp6wYiyIkMwVj3uohjTLg1jIsc2DKNJd6yeh8kNopQI4YYmXqZRWk4Xm+VZFY9nHk+GVZfkriFMUxDAOUczaPMwDBMAAAK2hSAgGTMIlygkIlsRdHgFaNU4wEkNYuwHEYkkJaJHicDQFEwB595eaVPkVdh07VWhun1RZ4VWb+NmCauR0nZJWQanen71CMURjB0XQ9CQA0pneH5DADzRAycUwzODfTVHe8ytdBTnAKw4ZGBWJXPuVk4zl+wDzq9FpDPtWPkEgOMRvjF2E+xE4kzx1mU2g1PdrC6bFNoWZ7nS4LeQp1YgHmi4iJK5YNqzADkLwYPLrMuD1JREAArAADLr8xNhLhxSzLcvAIrETy02QA
Could also go a little bit more complex to catch the case where delay: 0 is also synchronous, at the cost of showing something invalid for negative delays but a negative delay is technically nonsense:
https://www.typescriptlang.org/play?#code/FAehAIBEFMDMEsB28Au8D2iDO4BGBPALnAHUBXcACQEN01rFwAeACxRQActCwBzVFmVwA6AMboAtiADubLAGt8APmDQAHh3QAnFOCQpoW2NVHRwASQAq+DtADyHFDgDewcOAXwOAYQA28UXkAfmJcdHRfaAY3D3kvAEEyFHQ-dCxoELxwyOj3ABNoX2p8TMQyCVxDGKRUeGpfAGVC6FE0TAaUah1S8sqtauR6RubWjEQAUUQ8noqqgF9gVQ1tXRQbM0su3mgUcciJaERdAF5wPegDo-AAH1IkPPRpRYLRIq0zcWxdMnStcYA3Q4oYiudxrWzEJiWcDqAxTHBWdYOJxKAAUMXczUuwPAmy0212+yBABoMeADGocVgUFokLxSe53D9DMisJkAEpRB6IXz4KFKBngACU4GOSlxMMphzyLnABSKRHAAAZwAtGeAguB-uh4HkycRobDpbL5cViGVZlpVWT3JqAApaSTwdJMbW6lTq9zEN16hbAF5vD6YankvYGrY7c7Y4CfEPOgBqOryovAzL+gKOwnB0FRhOJ4AA5LBwgX8845YUzcrVUKY8HdM6HU70im0wCgVn1rm9vmiyWyxWFcQAIwqua12MNrDxXxYdCJ3Wt37tzPZ7u+XvF9AF2ugCBIcRad6tcnrcDvFBkLSMXBJcD1OfgRB0c9RXy8++MJAcO8oFjUXQDgYHAGHwP86SCOsvj0adZ3QJsJGdMxTjbDMUE7Wx103ftwHLU1FQAWlHMchSAA
oh lol delay is a number, not a boolean. My bad 馃槅 I guess it still applies the same idea
edit: I updated the PR details and title to reflect it is a number and not a boolean
@laquasicinque As clever as extends {delay: 0} is, it's unfortunately not very practical. Most users will be used to {delay: 0}, which is widened to the type {delay: number}, which will fail this check and return a Promise, which leads to the original issue here. While users could use {delay: 0 as const}, it's not very easy to learn, and I think going with a slightly more naive type is better than a confusing error message. Thanks for the idea though.
I have committed @ljosberinn's types from https://github.com/testing-library/user-event/issues/480#issuecomment-721288992 and added tests in #491.
Thanks, it looks great! 馃殌
Most helpful comment
I have committed @ljosberinn's types from https://github.com/testing-library/user-event/issues/480#issuecomment-721288992 and added tests in #491.