line 129 is available. However, since we check each func-
tion signature in isolation, our static analysis does not ob-
serve the field established in setPosition when checking
getPosition. The expression el._leaflet_pos is thus de-
termined to return undefined, which fails to check against
the Point type, and our analysis thus issues a spurious warn-
ing regarding the return type of getPosition.
6.2 Limitations in TypeScript
The high-impact warnings for the sugar library are shown
in parentheses because it is clear from the declaration file
that the developer is already aware of all of them. The bugs
are currently unfixable due to a limitation in TypeScript that
makes it impossible to extend the type of a variable that was
defined in TypeScript’s prelude declaration file (the prelude
is implicitly included from all other declaration files, similar
to the java.lang package in Java). These warnings were all
reported by the first phase of the algorithm.
We observed another limitation of TypeScript in the dec-
laration file for the leaflet library. This library configures
itself based on the presence of certain global variables, such
as L_DISABLE_3D, intended to be set by the client. It is help-
ful for the declaration file to document these variables, but
the variables are absent by default, and global variables can-
not be declared optional in TypeScript (though our core lan-
guage allows it). To spare the user from such low-impact
warnings that cannot be fixed, we configured our analyzer
to omit all warnings regarding missing boolean properties if
the property occurs in a position where it cannot be declared
optional.
Lastly, we observed that the threejs library declares
several enum types with no members, because the members
of the enum are not encapsulated in a namespace object like
TypeScript expects, as shown in the following fragment:
136 enum CullFace { }
137 var CullFaceBack: CullFace;
138 var CullFaceFront: CullFace;
To compensate, we configured our analyzer to treat empty
enums as the any type.
None of these limitations exist in TypeScript Declaration
Core (Section 2.1), so a more liberal syntax for TypeScript
would alleviate the issues.
7. Related Work
Most high-level programming languages provide interfaces
to libraries written in low-level languages. The challenge of
ensuring consistency between the low-level library code and
the high-level interface descriptions has been encountered
for other languages than TypeScript and JavaScript. Furr
and Foster have studied the related problem of type check-
ing C code that is accessed via the foreign function inter-
faces of Java or OCaml [3]. Due to the major differences
between JavaScript and C and between the notion of types
in TypeScript compared to those in Java or OCaml, their
type inference mechanism is not applicable to our setting.
St-Amour and Toronto have proposed using random testing
to detect errors in the base environment for Typed Racket
numeric types, which are implemented in C [13]. We be-
lieve it is difficult to apply that technique to TypeScript types
and JavaScript libraries, since TypeScript types are consider-
ably more complex than the numeric types in Typed Racket.
Another essential difference between these languages is that
JavaScript libraries are initialized dynamically without any
static declaration of types and operations, which we have
chosen to address by the use of heap snapshots.
The dynamic heap type inference technique by Pol-
ishchuk et al. [11] is related to our snapshot type check-
ing phase (Section 4), but is designed for C instead of
TypeScript, which has a different notion of types. Unlike
C, JavaScript and TypeScript are memory-safe languages
where all runtime values are typed (with JavaScript types,
not TypeScript types), and we can disregard the call stack,
which leads to a simpler algorithm in our setting.
To the best of our knowledge, no previous work has ad-
dressed the challenge of automatically finding errors in li-
brary interface descriptions for JavaScript, nor for dynami-
cally typed programming languages in general. TypeScript
is by design closely connected to JavaScript, but other stati-
cally typed languages, such as Dart [5] or Java via GWT [4],
contain similar bindings to JavaScript, to enable applications
to build upon existing JavaScript libraries. Despite the young
age of TypeScript, the immense volume of the Definitely
Typed repository testifies to the popularity of the language
and the importance of interacting with JavaScript libraries.
Several more expressive type systems for JavaScript
than the one in TypeScript have been proposed, including
TeJaS [9] and DJS [1]. We only use TypeScript’s meaning
of types, not its rules for type checking program code, and
it may be possible to adapt our system to such alternative
type systems, if they were to introduce language bindings to
JavaScript libraries.
The static analysis in Section 5 is a unification-based
analysis in the style of Steensgaard [14] and bears some re-
semblance to the one used in our previous work on refac-
toring [2], although that work did not deal with function
calls, prototype-based inheritance, dynamic property access,
heap snapshots, or types. Many other static analysis tech-
niques have been developed for JavaScript, for example,
TAJS, which is designed to detect type-related errors in
JavaScript applications [7], WALA [12], and Gatekeeper [6].
None of these incorporate type declarations into the analysis,
and they focus on soundness, not performance.
A potential alternative to our approach could be to apply
hybrid type checking [8] by instrumenting the program code
to perform runtime checks at the boundary between Type-
Script applications and JavaScript libraries. By the use of
static analysis, we avoid the need for instrumentation and
high-coverage test suites.