jsii
can only accept APIs that can be represented in all the supported target
languages, and TypeScript is a feature-rich, modern programming language. As a
consequence, jsii
needs to impose restrictions on what TypeScript language
features can be used. Certain common Javascript idioms are also interpreted
specially by jsii
in order to support providing a more consistent developer
experience across various languages.
As jsii
only needs to represent those types that are part of the exported
APIs of the package, the restrictions outlined in this document do not apply to
private (or internal) types and functions.
jsii
will emit warnings if reserved words are used as identifiers for any API
element (which will cause a compilation failure if --fail-on-warnings
is set).
The list of reserved words (which are not also reserved in TypeScript),
derived from jsii/lib/reserved-words.ts
is:
C# | Java | Python |
---|---|---|
abstract |
abstract |
False |
base |
assert |
None |
bool |
boolean |
True |
byte |
byte |
and |
char |
char |
assert |
checked |
double |
def |
decimal |
final |
del |
delegate |
float |
elif |
double |
goto |
except |
event |
int |
from |
explicit |
long |
global |
extern |
native |
is |
fixed |
short |
lambda |
float |
strictfp |
nonlocal |
foreach |
synchronized |
not |
goto |
throws |
or |
implicit |
transient |
pass |
int |
volatile |
raise |
internal |
||
is |
||
lock |
||
long |
||
namespace |
||
object |
||
operator |
||
out |
||
override |
||
params |
||
readonly |
||
ref |
||
sbyte |
||
sealed |
||
short |
||
sizeof |
||
stackalloc |
||
string |
||
struct |
||
uint |
||
ulong |
||
unchecked |
||
unsafe |
||
ushort |
||
using |
||
virtual |
||
volatile |
Code generators from jsii-pacmak
will try to work around those reserved words
when they are encountered, but may resort to using names that could clash with
other identifiers used in your API, or result in suboptimal experience for
users in languages with conflicts.
Methods and properties declared on classes cannot be named after the class ( meaning they cannot share the same PascalCased representation), as this results in illegal C# code:
📝 Due to existing usage (in such cases, an
_
is appended at the end of the type name, effectively breaking existing .NET code if such a member is introduced post-release), this restriction is only enforced whenjsii
is invoked with the--strict
parameter.It will be upgraded to always be an error in a future release.
export class Name {
// ⛔️ Illegal property name
public name: string;
}
export class Name {
// ⛔️ Illegal method name
public name(): void { /* ... */ }
}
The visibility of a type member cannot be changed when it is overridden, even if the change increases the visibility of said member, as this would result in illegal C# code:
export class Base {
protected method(): void { /* ... */ }
}
export class Child {
// ⛔️ Illegal change of visibility when overriding a member
public method(): void { /* ... */ }
}
Additionally, C# does not allow changing the type signature of members while
overriding them, even if the updated type signature is a strict specialization
of the original one, and this is consequently also forbidden in jsii
:
export class Base {
public method(): any { /* ... */ }
}
export class Child {
// ⛔️ Illegal change of signature when overriding a member
public method(): string { /* ... */ }
}
jsii
considers TypeScript interfaces in two distinct categories: Structs
and Behavioral Interfaces. Both of those entities are represeted using
TypeScript interfaces, but have distinct sets of requirements.
Behavioral interfaces are the specification of a contract that a type can elect
to adhere to. They can define a number of public
members which can be
properties or methods. jsii
requires that behavioral interfaces have names
prefixed with an uppercase I
.
// ⛔️ Illegal name
export interface Foo { /* ... */ }
// ✅ Legal
export interface IFoo { /* ... */ }
// ⛔️ Illegal name
export interface InstanceProvider { /* ... */ }
// ✅ Legal
export interface IInstanceProvider { /* ... */ }
// ⛔️ Illegal extension of a struct
export interface IBar extends SomeStruct { /* ... */ }
Interfaces can be implemented by classes or extended by other interfaces, but may not extend (or be extended by) structs.
Structs, on the other hand, are pure data constructs. They may not declare
methods, only readonly
properties. Those types model what Javascript
developers use to model keyword arguments, where they typically pass an object
literal with configuration values to a method or constructor. Structs do not
have names starting with an uppercase I
(making it possible to define a
behavioral interface that only declares read-only properties as part of its
contract).
// ⛔️ Illegal
export interface Foo {
foo(): void; // Structs cannot define methods
}
// ⛔️ Illegal
export interface Bar {
foo: number; // Struct members must be readonly
}
// ✅ Legal
export interface Baz {
readonly foo: number;
}
// ⛔️ Illegal extension of a behavioral interface
export interface SomeStruct extends IBehavioralInterface { /* ... */ }
// ✅ Legal
export interface SomeStruct extends OtherStruct { /* ... */ }
// ⛔️ Illegal implementation of a struct
export class BazImpl implements Baz { /* ... */ }
Structs can be extended by other structs, but may not extend (or be extended by) behavioral interfaces, nor can they be implemented by classes.
Due to the lack of a generics concept in certain candidate programming
languages (such as go), TypeScript parameterized types are not
supported by jsii
, with the exception of standard promises (Promise<T>
) as
well as arrays (Array<T>
, which is equivalent to T[]
).
// ⛔️ Illegal
export interface Provider<ValueType> {
get(): ValueType;
}
// ✅ Legal
export interface AsyncFooMaker {
makeFoo(): Promise<Bar>;
makeFoos(count: number): Array<Promise<Bar>>;
}