Skip to content

Commit 5fded74

Browse files
authored
Document const enum pitfalls and workarounds
1 parent 96eb5f5 commit 5fded74

File tree

1 file changed

+25
-0
lines changed
  • packages/documentation/copy/en/reference

1 file changed

+25
-0
lines changed

packages/documentation/copy/en/reference/Enums.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,31 @@ let directions = [
365365
];
366366
```
367367

368+
#### Const enum pitfalls
369+
370+
Inlining const enum values is straightforward at first, but comes with subtle implications.
371+
These pitfalls pertain to _ambient_ const enums only (basically const enums in `.d.ts` files) and sharing const enums between projects, but because `tsc --declaration` transforms `.ts` files into `.d.ts` files, if you are publishing or consuming `.d.ts` files, these pitfalls likely apply to you.
372+
373+
1. For the reasons laid out in the [`isolatedModules` documentation](/tsconfig#references-to-const-enum-members), that mode is fundamentally incompatible with ambient const enums.
374+
This means if you publish ambient const enums, downstream consumers will not be able to use [`isolatedModules`](/tsconfig#isolatedModules) and those values at the same time.
375+
2. You can easily inline values from version A of a dependency at compile time, and import version B at runtime.
376+
Version A and B's enums can have different values, if you are not very careful, resulting in [surprising bugs](https://github.com/microsoft/TypeScript/issues/5219#issue-110947903), like taking the wrong branches of `if` statements.
377+
These bugs are especially pernicious because it is common to build and run automated tests at the same time, with the same dependency versions, which does not exercise them at all.
378+
3. [`importsNotUsedAsValues: "preserve"`](/tsconfig#importsNotUsedAsValues) will not elide imports for const enums used as values, but ambient const enums do not guarantee that runtime `.js` files exist, and the unresolvable import will cause an error at runtime.
379+
The usual way to unambiguously elide imports, [type-only imports](/docs/handbook/modules.html#importing-types), [does not allow const enum values](https://github.com/microsoft/TypeScript/issues/40344), currently.
380+
381+
Here are two approaches to avoiding these pitfalls:
382+
383+
A. Do not use const enums entirely.
384+
You can easily [ban const enums](https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/FAQ.md#how-can-i-ban-specific-language-feature) with the help of a linter.
385+
Obviously this avoids any issues with const enums, but prevents your project from inlining its own enum values.
386+
Inlining a project's own enum values is not problematic and has performance implications.
387+
B. Do not publish ambient const enums, by deconstifying them with the help of [`preserveConstEnums`](/tsconfig#preserveConstEnums).
388+
This is the approach taken internally by the [TypeScript project itself](https://github.com/microsoft/TypeScript/pull/5422).
389+
[`preserveConstEnums`](/tsconfig#preserveConstEnums) emits the same JavaScript for const enums as plain enums, and you can then safely strip the `const` modifier from `.d.ts` files [in a build step](https://github.com/microsoft/TypeScript/blob/1a981d1df1810c868a66b3828497f049a944951c/Gulpfile.js#L144).
390+
391+
This way downstream consumers will not inline enum values from your project, which avoids the pitfalls above, but a project can still inline its own const enum values, unlike in the first approach.
392+
368393
## Ambient enums
369394

370395
Ambient enums are used to describe the shape of already existing enum types.

0 commit comments

Comments
 (0)