The following TypeScript features can not be erased by ts-blank-space
because they have runtime semantics
enum
(unlessdeclare enum
) more detailsnamespace
(unless only contains types) more detailsmodule
(unlessdeclare module
) more detailsimport lib = ...
,export = ...
(TypeScript style CommonJS)constructor(public x) {}
more details
For more details on use of declare
see the declare
hazard.
The following enum
declaration will not be transformed by ts-blank-space
.
enum Direction {
North,
South,
East,
West,
}
An alternative approach to defining an enum like value and type, which is ts-blank-space
compatible:
const Direction = {
North: 1,
South: 2,
East: 3,
West: 4,
} as const;
type Direction = (typeof Direction)[keyof typeof Direction];
// ^? = 1 | 2 | 3 | 4
The following usage of a constructor parameter property will not be transformed by ts-blank-space
.
class Person {
constructor(public name: string) {}
// ^^^^^^
}
The equivalent ts-blank-space
compatible approach:
class Person {
public name;
constructor(name: string) {
this.name = name;
}
}
While sharing the same syntax there are technically two categories of namespace
within TypeScript. Instantiated and non-instantiated. Instantiated namespaces create objects that exist at runtime. Non-instantiated namespaces can be erased. A namespace is non-instantiated if it only contains types - more specifically it may only contain:
- type aliases:
[export] type A = ...
- interfaces:
[export] interface I { ... }
- Importing types from other namespaces:
import A = OtherNamespace.X
- More non-instantiated namespaces (the rule is recursive)
ts-blank-space
will always erase non-instantiated namespaces and namespaces marked with declare
.
Examples of supported namespace syntax can be seen in the test fixture tests/fixture/cases/namespaces.ts. Error cases can be seen in tests/errors.
ts-blank-space
only erases TypeScript's module
namespace declarations if they are marked with declare
(see declare
hazard).
All other TypeScript module
declarations will trigger the onError
callback and be left in the output text verbatim. Including an empty declaration:
module M {} // `ts-blank-space` error
Note that, since TypeScript 5.6, use of module
namespace declarations (not to be confused with "ambient module declarations") will be shown with a strike-through () to hint that the syntax is deprecated in favour of module
namespace
.
See microsoft/TypeScript#51825 for more information.
Note: This section describes a potential hazard in the TypeScript language that exists with or without ts-blank-space
.
It is described here only because adopting type-stripping may lead to developers reaching for declare
as part of migration.
As with declare const ...
, while ts-blank-space
will erase syntax such as declare enum ...
and declare namespace ...
without error it should be used with understanding and mild caution.
declare
in TypeScript is an assertion by the author that a value will exist at runtime.
For example:
declare namespace N {
export const x: number;
}
console.log(N.x);
The above will not be a build time error and will be transformed to:
console.log(N.x);
So it may throw at runtime if nothing created a runtime value for N
as promised by the declare
.
Tests are a great way to catch issues that may arise from an incorrect declare
.
TypeScript type assertions have no runtime semantics, however ts-blank-space
does not erase the legacy prefix-style type assertions.
const x = <const>{ a: 1 };
// ^^^^^^^ not erased by `ts-blank-space`
In 2015 TypeScript 1.6 added an alternative style, which ts-blank-space
does support. The above can be re-written as:
const x = { a: 1 } as const;
Which ts-blank-space
will transform to:
const x = { a: 1 } ;
The as
style also has the advantage of not conflicting with JSX syntax.
The reason ts-blank-space
doesn't support the prefix style is because there are situations where erasing it would change the runtime semantics of the remaining JavaScript.
function foo() {
return <const>
[];
}
Erasing the type assertion would result in the following incorrect output:
function foo() {
return
[];
}
Because of the new-line after return
the above function is actually the same as:
function foo() {
return;
}
One possible approach ts-blank-space
could take to retain the original semantics is to insert some JavaScript:
function foo() {
return 0,
[];
}
However there are other places where prefix-style type-assertions can't be erased:
const fn = () => <const>{};
Erasing the type assertion would result in the following incorrect output:
const fn = () => {};
The above function is the same as:
const fn = () => {
return;
};
The comma-operator approach above doesn't work here because the comma (,
) could represent the end of the expression:
function foo(arg1 = () => 1, arg2 = 2) {
// ^ comma marks the end of the first argument
}
An alternative way for ts-blank-space
to fix up the output by adding JavaScript could be:
const fn = () => 0||{};
But this doesn't work for the following input:
const fn = () => <const>{ p: a }.p ?? b;
Because the following output is a syntax error:
const fn = () => 0||{ p: a }.p ?? b;
Due to the following:
- There does not appear to be a universal strategy for erasing prefix type assertions
- Potential solutions involve injecting JavaScript not present in the input
- Adding parenthesis
(
)
to the output requires generating a sourcemap <const>val
can be re-written toval as const
ts-blank-space
has decided to not support the prefix style.