Skip to content

lib.d.ts types are too loose: provide a version without vars declared? #327

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

Open
JoshuaKGoldberg opened this issue Nov 21, 2017 · 2 comments

Comments

@JoshuaKGoldberg
Copy link
Contributor

JoshuaKGoldberg commented Nov 21, 2017

(Porting microsoft/TypeScript#20175)

A lot of teams have seen production bugs from trying to use code not available in older browsers. performance.now, for example, is listed in lib.d.ts but shouldn't be used on sites that support IE10 and don't polyfill performance.

Two other ways of getting around this class of problem without dropping browsers or adding polyfills (are there other good ones?) are:

  • Manually banning scores of built-in types with TSLint
  • Dropping "dom" from "lib" in tsconfig.json

Removing "dom" typings works great to enforce using only non-browser APIs (or dependency-injecting them where used), which is much better than calling APIs like performance.now and setTimeout willy nilly. However, you now need to manually re-write typings for all these native things as you go.

The solution would be much simpler if TypeScript exposed a form of lib.d.ts that included only the interfaces and types for all these constructs without the declare var/declare function.

Using setTimeout as an example, it's declared without a separate ISetTimeout interface in TypeScript's lib.d.ts:

declare function setTimeout(handler: (...args: any[]) => void, timeout: number): number;
declare function setTimeout(handler: any, timeout?: any, ...args: any[]): number;

interface WindowTimers extends Object, WindowTimersExtension {
    // ...
    setTimeout(handler: (...args: any[]) => void, timeout: number): number;
    setTimeout(handler: any, timeout?: any, ...args: any[]): number;
}

If it were changed to provide an ISetTimeout it would be much easier to use setTimeout without a reliance on the browser+Node API.

interface SetTimeout {
    (handler: (...args: any[]) => void, timeout: number): number;
    (handler: any, timeout?: any, ...args: any[]): number;
}

interface WindowTimers extends Object, WindowTimersExtension {
    // ...
    setTimeout: SetTimeout;
}
// Only in the standard ("loose") version:
declare var setTimeout: SetTimeout;

Errata: I personally remove "dom" whenever possible.. but a lot of @types definitions assume it exists and it's a bit like whack-a-mole trying to fix typings on DefinitelyTyped to work in dom-less repos.

Edit: some DefinitelyTyped issues this causes:

@sod
Copy link

sod commented Jan 30, 2019

I second this. Today I did

const element = document.querySelector<Element>('.an-element');

if (element) {
    element.remove();
}

This failed in IE11, as remove is not available there. You have to do element.parentNode.removeChild(element). But typescript didn't complain as remove() is just declared on Element

@yw662
Copy link

yw662 commented Jul 1, 2019

microsoft/TypeScript#32186

It seems can be solved by:

declare function setTimeout<A extends any[]>(handler: (...args: A) => void, timeout?: number, ...arguments: A): number;
declare function setTimeout(handler: string, timeout?: number, ...arguments: any[]): number;
declare function setInterval<A extends any[]>(handler: (...args: A) => void, timeout?: number, ...arguments: A): number;
declare function setInterval(handler: string, timeout?: number, ...arguments: any[]): number;

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

No branches or pull requests

3 participants