Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support enum-like objects with numeric literal values #1920

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions example/src/enums.ts
Expand Up @@ -51,3 +51,27 @@ export const EnumLikeObject = {

Completed: "completed",
} as const;

/**
* Since TypeScript's `enum` can be inconvenient to work with, some packages define their own enum-like objects:
*
* ```
* export const EnumLikeObjectNumValues = {
* Pending: 1,
* InProgress: 2,
* Completed: 3
* } as const
* ```
*
* Use the `@enum` tag to make TypeDoc document this object as an enum.
*
* @enum
*/
export const EnumLikeObjectNumValues = {
Pending: 1,

/** Indicates that a courier is en route delivering this order. */
InProgress: 2,

Completed: 3,
} as const;
4 changes: 2 additions & 2 deletions src/lib/converter/symbols.ts
Expand Up @@ -881,7 +881,7 @@ function isEnumLike(checker: ts.TypeChecker, type: ts.Type, location: ts.Node) {

return type.getProperties().every((prop) => {
const propType = checker.getTypeOfSymbolAtLocation(prop, location);
return propType.isStringLiteral();
return propType.isStringLiteral() || propType.isNumberLiteral();
});
}

Expand Down Expand Up @@ -912,7 +912,7 @@ function convertVariableAsEnum(
prop,
declaration
);
assert(propType.isStringLiteral());
assert(propType.isStringLiteral() || propType.isNumberLiteral());

reflection.defaultValue = JSON.stringify(propType.value);

Expand Down
38 changes: 38 additions & 0 deletions src/test/behaviorTests.ts
Expand Up @@ -39,6 +39,44 @@ export const behaviorTests: Record<

const WithoutReadonly = query(project, "WithoutReadonly");
equal(WithoutReadonly.kind, ReflectionKind.Enum, "WithoutReadonly");

const SomeEnumLikeNumeric = query(project, "SomeEnumLikeNumeric");
equal(
SomeEnumLikeNumeric.kind,
ReflectionKind.Variable,
"SomeEnumLikeNumeric"
);
const SomeEnumLikeTaggedNumeric = query(
project,
"SomeEnumLikeTaggedNumeric"
);
equal(
SomeEnumLikeTaggedNumeric.kind,
ReflectionKind.Enum,
"SomeEnumLikeTaggedNumeric"
);
const B = query(project, "SomeEnumLikeTaggedNumeric.b");
equal(B.defaultValue, "1");

const ManualEnumNumeric = query(project, "ManualEnumNumeric");
equal(ManualEnumNumeric.kind, ReflectionKind.Enum, "ManualEnumNumeric");

const ManualWithoutHelperNumeric = query(
project,
"ManualEnumHelperNumeric"
);
equal(
ManualWithoutHelperNumeric.kind,
ReflectionKind.Enum,
"ManualEnumHelperNumeric"
);

const WithoutReadonlyNumeric = query(project, "WithoutReadonlyNumeric");
equal(
WithoutReadonlyNumeric.kind,
ReflectionKind.Enum,
"WithoutReadonlyNumeric"
);
},
duplicateHeritageClauses(project) {
const b = query(project, "B");
Expand Down
30 changes: 30 additions & 0 deletions src/test/converter2/behavior/asConstEnum.ts
@@ -1,3 +1,5 @@
/* Enum-like objects with string literal values */

export const SomeEnumLike = {
a: "a",
b: "b",
Expand All @@ -23,3 +25,31 @@ export const ManualEnumHelper: Readonly<{ a: "a" }> = {
export const WithoutReadonly = {
a: "a",
} as { a: "a" };

/* Enum-like objects with numeric literal values */

export const SomeEnumLikeNumeric = {
Gerrit0 marked this conversation as resolved.
Show resolved Hide resolved
a: 0,
b: 1,
} as const;

/** @enum */
export const SomeEnumLikeTaggedNumeric = {
a: 0,
b: 1,
} as const;

/** @enum */
export const ManualEnumNumeric: { readonly a: 0 } = {
a: 0,
};

/** @enum */
export const ManualEnumHelperNumeric: Readonly<{ a: 0 }> = {
a: 0,
};

/** @enum */
export const WithoutReadonlyNumeric = {
a: 0,
} as { a: 0 };