Skip to content

Commit 261b5a1

Browse files
committed
Add type information to enum members
Resolves #1942.
1 parent f82abcb commit 261b5a1

File tree

21 files changed

+152
-50
lines changed

21 files changed

+152
-50
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
- Added support for TypeScript 4.7, #1935.
66
- Support enum-like objects with numeric literal values tagged with `@enum`, #1918.
7+
- Enum member reflections will now have their `type` set to either a `LiteralType` with a string or numeric value or an `IntrinsicType` with type `number`, #1942.
8+
Using `defaultValue` on `EnumMember` reflections is now deprecated, and will be broken in 0.23.
79

810
### Bug Fixes
911

1012
- Fixed invalid type output in some uncommon edge cases, TypeDoc also now renders fewer superfluous parenthesis when creating types.
13+
- TypeDoc is now more consistent about ordering with `enum-value-ascending` or `enum-value-descending` sort strategies in mixed string/number enums.
1114

1215
### Thanks!
1316

@@ -844,7 +847,7 @@
844847
- isExternal flag wasn't set properly
845848
- JSON schema had incorrect value types, closes #1389
846849
- Hidden module-namespaces, closes #1396
847-
- Some issues with inheritence
850+
- Some issues with inheritance
848851
- We pick up all properties now
849852
- Support for specify a directory as an entry point
850853
- Lint
@@ -963,7 +966,7 @@
963966
- Missed a test configuration update
964967
- Rename external modules to modules, closes #109
965968
- Check for compiler errors before converting
966-
- Moved @types/minimatch dependency to devDepencencies (#1206)
969+
- Moved @types/minimatch dependency to devDependencies (#1206)
967970
- Plugin resolution for relative paths (#1194), closes #1188
968971

969972
### Thanks!

scripts/rebuild_specs.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,10 @@ function rebuildConverterTests(dirs) {
8585
);
8686
const serialized = app.serializer.toObject(result);
8787

88-
const data = JSON.stringify(serialized, null, " ")
89-
.split(TypeDoc.normalizePath(base))
90-
.join("%BASE%");
88+
const data =
89+
JSON.stringify(serialized, null, " ")
90+
.split(TypeDoc.normalizePath(base))
91+
.join("%BASE%") + "\n";
9192
after();
9293
fs.writeFileSync(out.replace("dist", "src"), data);
9394
}

src/lib/converter/symbols.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import * as assert from "assert";
22
import * as ts from "typescript";
33
import {
44
DeclarationReflection,
5+
IntrinsicType,
6+
LiteralType,
57
ReferenceReflection,
68
Reflection,
79
ReflectionFlag,
@@ -245,11 +247,18 @@ function convertEnumMember(
245247
exportSymbol
246248
);
247249

248-
reflection.defaultValue = JSON.stringify(
249-
context.checker.getConstantValue(
250-
symbol.getDeclarations()![0] as ts.EnumMember
251-
)
250+
const defaultValue = context.checker.getConstantValue(
251+
symbol.getDeclarations()![0] as ts.EnumMember
252252
);
253+
reflection.defaultValue = JSON.stringify(defaultValue);
254+
255+
if (defaultValue !== undefined) {
256+
reflection.type = new LiteralType(defaultValue);
257+
} else {
258+
// We know this has to be a number, because computed values aren't allowed
259+
// in string enums, so otherwise we would have to have the constant value
260+
reflection.type = new IntrinsicType("number");
261+
}
253262

254263
context.finalizeDeclarationReflection(reflection, symbol, exportSymbol);
255264
}
@@ -657,16 +666,10 @@ function convertProperty(
657666
}
658667
reflection.defaultValue = declaration && convertDefaultValue(declaration);
659668

660-
// FIXME: This is a horrible hack because getTypeOfSymbol is not exposed.
661-
// The right solution here is probably to keep track of parent nodes...
662-
// but that's tricky because not every reflection is guaranteed to have a
663-
// parent node. This will probably break in a future TS version.
664669
reflection.type = context.converter.convertType(
665670
context,
666671
(context.isConvertingTypeNode() ? parameterType : void 0) ??
667-
context.checker.getTypeOfSymbolAtLocation(symbol, {
668-
kind: ts.SyntaxKind.SourceFile,
669-
} as any)
672+
context.checker.getTypeOfSymbol(symbol)
670673
);
671674

672675
if (reflection.flags.isOptional) {
@@ -896,6 +899,7 @@ function convertVariableAsEnum(
896899
assert(propType.isStringLiteral() || propType.isNumberLiteral());
897900

898901
reflection.defaultValue = JSON.stringify(propType.value);
902+
reflection.type = new LiteralType(propType.value);
899903

900904
rc.finalizeDeclarationReflection(reflection, prop, void 0);
901905
}

src/lib/models/reflections/declaration.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ export class DeclarationReflection extends ContainerReflection {
7979
* The default value of this reflection.
8080
*
8181
* Applies to function parameters.
82+
*
83+
* Note: Using this for enum members is DEPRECATED and will be removed in 0.23.
8284
*/
8385
defaultValue?: string;
8486

src/lib/output/themes/default/partials/member.declaration.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DeclarationReflection, ReflectionType } from "../../../../models";
1+
import { DeclarationReflection, ReflectionKind, ReflectionType } from "../../../../models";
22
import { JSX } from "../../../../utils";
33
import { renderTypeParametersSignature, wbr } from "../../lib";
44
import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext";
@@ -14,7 +14,7 @@ export const memberDeclaration = (context: DefaultThemeRenderContext, props: Dec
1414
{context.type(props.type)}
1515
</>
1616
)}
17-
{!!props.defaultValue && (
17+
{!!props.defaultValue && props.kind !== ReflectionKind.EnumMember && (
1818
<>
1919
<span class="tsd-signature-symbol">
2020
{" = "}

src/lib/types/ts-internal/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ declare module "typescript" {
2020
getTypePredicateOfSignature(
2121
signature: ts.Signature
2222
): ts.TypePredicate | undefined;
23+
24+
//https://github.com/microsoft/TypeScript/blob/v4.7.2/src/compiler/types.ts#L4188
25+
getTypeOfSymbol(symbol: Symbol): Type;
2326
}
2427

2528
export interface Signature {

src/lib/utils/sort.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { ReflectionKind } from "../models/reflections/kind";
77
import type { DeclarationReflection } from "../models/reflections/declaration";
8+
import { LiteralType } from "../models";
89

910
export const SORT_STRATEGIES = [
1011
"source-order",
@@ -59,10 +60,12 @@ const sorts: Record<
5960
a.kind == ReflectionKind.EnumMember &&
6061
b.kind == ReflectionKind.EnumMember
6162
) {
62-
return (
63-
parseFloat(a.defaultValue ?? "0") <
64-
parseFloat(b.defaultValue ?? "0")
65-
);
63+
const aValue =
64+
a.type instanceof LiteralType ? a.type.value : -Infinity;
65+
const bValue =
66+
b.type instanceof LiteralType ? b.type.value : -Infinity;
67+
68+
return aValue! < bValue!;
6669
}
6770
return false;
6871
},
@@ -71,10 +74,12 @@ const sorts: Record<
7174
a.kind == ReflectionKind.EnumMember &&
7275
b.kind == ReflectionKind.EnumMember
7376
) {
74-
return (
75-
parseFloat(b.defaultValue ?? "0") <
76-
parseFloat(a.defaultValue ?? "0")
77-
);
77+
const aValue =
78+
a.type instanceof LiteralType ? a.type.value : -Infinity;
79+
const bValue =
80+
b.type instanceof LiteralType ? b.type.value : -Infinity;
81+
82+
return bValue! < aValue!;
7883
}
7984
return false;
8085
},
@@ -138,11 +143,11 @@ const sorts: Record<
138143
};
139144

140145
export function sortReflections(
141-
strategies: DeclarationReflection[],
142-
strats: readonly SortStrategy[]
146+
reflections: DeclarationReflection[],
147+
strategies: readonly SortStrategy[]
143148
) {
144-
strategies.sort((a, b) => {
145-
for (const s of strats) {
149+
reflections.sort((a, b) => {
150+
for (const s of strategies) {
146151
if (sorts[s](a, b)) {
147152
return -1;
148153
}

src/test/behaviorTests.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { deepStrictEqual as equal, ok } from "assert";
22
import {
33
DeclarationReflection,
4+
LiteralType,
45
ProjectReflection,
56
ReflectionKind,
67
} from "../lib/models";
@@ -25,6 +26,7 @@ export const behaviorTests: Record<
2526
"SomeEnumLikeTagged"
2627
);
2728
const A = query(project, "SomeEnumLikeTagged.a");
29+
equal(A.type, new LiteralType("a"));
2830
equal(A.defaultValue, '"a"');
2931

3032
const ManualEnum = query(project, "ManualEnum");
@@ -56,6 +58,7 @@ export const behaviorTests: Record<
5658
"SomeEnumLikeTaggedNumeric"
5759
);
5860
const B = query(project, "SomeEnumLikeTaggedNumeric.b");
61+
equal(B.type, new LiteralType(1));
5962
equal(B.defaultValue, "1");
6063

6164
const ManualEnumNumeric = query(project, "ManualEnumNumeric");

src/test/converter/comment/specs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,4 +361,4 @@
361361
]
362362
}
363363
]
364-
}
364+
}

src/test/converter/declaration/specs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,4 @@
241241
]
242242
}
243243
]
244-
}
244+
}

0 commit comments

Comments
 (0)