Skip to content

Treat broken types in declaration files as unknown rather than anyΒ #56125

Closed
@frigus02

Description

@frigus02

πŸ” Search Terms

skipLibCheck, noImplicitAny clash, broken type, any, unknown

βœ… Viability Checklist

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

⭐ Suggestion

In case of an error (e.g. duplicated identifier) in declaration files, TypeScript treats types related to the error as any. I suggest that TypeScript uses unknown instead.

This could be implemented with a new strictness option.

πŸ“ƒ Motivating Example

Repro: https://github.com/frigus02/test-ts-skiplibcheck | on TS bug workbench

Setup:

  • 2 different TypeScript libraries declare the same identifier with a different (incompatible) type, either using declare global or declare module. Individually both libraries build and run correctly.

    E.g. libraries a and b both declare a global identifier lib. a declares it as type string, b as a namespace containing identifier bees.

  • One library somehow exposes a type inside of the duplicated identifier.

    E.g. library b exports a function returning typeof lib.bees.

  • A third library brings imports both a and b.

Result:

  • Duplicated identifier lib is an error. The first seen declaration wins. Uses of the type as declared in the second declaration degenerate to any.

  • If main uses skipLibCheck: true, this is only noticeable when you trigger noImplicitAny, e.g. via a callback like .forEach(x =>. This may be rare and any can spread to other libraries. When an error does finally occur it can be really hard to track down where it's coming from.

πŸ’» Use Cases

  1. What do you want to use this for?

    Detect errors early. Prevent spread of any.

    Internally at Google we're still using https://github.com/angular/clutz for interop between TypeScript and Closure JavaScript. Clutz generates global namespaces. Every now and then 2 files generate the same identifier resulting in a clash as shown above.

    Applications also sometimes end up with multiple versions of declaration files for the same third party library (brought in via different transitive dependencies), which can result in the same error. While that's a bug, a feature like this would help to avoid and debug these cases.

  2. What shortcomings exist with current approaches?

    skipLibCheck: false is not feasible for us, because of longer compile time.

  3. What workarounds are you using in the meantime?

    none

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions