October 31, 2023

N4JS Can Generate TypeScript Definitions

N4JS source code is transpiled into EcmaScript, making it an integral part of the JavaScript ecosystem. Within this ecosystem, it is utilized by various libraries. To facilitate this usage, N4JS now offers TypeScript type definition generation.

The growing popularity of TypeScript as a programming language is evident in the increasing number of TypeScript packages and the download rates of pure type definition packages. The latter are primarily provided by the Definitely Typed repository, which currently includes type definitions for 8,724 libraries. By enabling the N4JS transpiler to generate TypeScript definition files, N4JS projects can be seamlessly imported into TypeScript projects while maintaining type safety.

To activate the feature for '.d.ts' file generation, you can set the 'n4js->generator->d.ts' property to 'true' in the 'package.json' file. This setting applies to the entire project. In cases where multiple projects exist within a yarn workspace, the transpiler will respect projects that do not generate '.d.ts' files. In case type information gets exposed through a project that generates 'd.ts' files, those exposed types are cut off and will be treated as any types. When generating type information, import statements in 'd.ts' files may be added or removed, as some become obsolete while others are necessary.

Despite their superficial similarities, N4JS and TypeScript differ in various aspects. For example, N4JS allows interfaces to provide static properties, and N4JS enums offer static properties like the getter literals that returns all literals of an enum. In the corresponding 'd.ts' files, these interfaces and enums are split up into TypeScript interfaces and enums along with a namespace bearing the same name (making use of TypeScript declaration merging). The additional namespace contains all properties that are static in the N4JS source code.

To enable the use of built-in types, such as accessing N4JS reflection information, the transpiler also includes the file 'n4jsglobals.d.ts'. This file contains type information about reflection classes and provides types that mimic N4JS structural typing strategies (e.g. all readable fields/getters of a type C written as ~r~C in N4JS) using utility types of TypeScript. 

While N4JS and TypeScript may appear similar, they differ in several ways. For instance, TypeScript generics have the semantics of an implicit upper bound, written as C<? extends T> in Java, whereas N4JS generics are similar to Java and support both no explicit bounds, as well as upper or lower bounds (written as C<T>, C<? extends T>, and C<? super T>). Additionally, TypeScript does not support certain features, such as optional getters or setters. N4JS, on the other hand, supports this feature, treating a getter/setter pair as override-compatible to fields, which of course can be optional. These differences or unsupported language features in TypeScript may occasionally result in generated type definitions not aligning perfectly with respect to the runtime EcmaScript and/or N4JS source code. However, in the vast majority of cases, TypeScript type information significantly simplifies and accelerates the reuse of N4JS libraries in terms of coding assistance and type validation.

by Marcus Mews