diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9300c731f..af1a210b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Unreleased
+### Features
+
+- Added support for TypeScript 5.3, #2446.
+- TypeDoc will now render interfaces as code at the top of the page describing interfaces, #2449.
+ This can be controlled through the new `DefaultThemeRenderContext.reflectionPreview` helper.
+- Improved type rendering to highlight keywords differently than symbols.
+
### Bug Fixes
- Fixed automatic declaration file resolution on Windows, #2416.
@@ -11,6 +18,7 @@
- `@example` tag titles will now be rendered in the example heading, #2440.
- Correctly handle transient symbols in `@namespace`-created namespaces, #2444.
- TypeDoc no longer displays the "Hierarchy" section if there is no inheritance hierarchy to display.
+- Direct links to individual signatures no longer results in the signature being partially scrolled off the screen.
### Thanks!
diff --git a/package.json b/package.json
index 7ba671476..728328e5b 100644
--- a/package.json
+++ b/package.json
@@ -66,6 +66,7 @@
"doc:c": "node bin/typedoc --tsconfig src/test/converter/tsconfig.json",
"doc:c2": "node bin/typedoc --tsconfig src/test/converter2/tsconfig.json",
"doc:c2d": "node --inspect-brk bin/typedoc --tsconfig src/test/converter2/tsconfig.json",
+ "example": "cd example && node ../bin/typedoc",
"test:full": "c8 mocha --config .config/mocha.full.json",
"test:visual": "ts-node ./src/test/capture-screenshots.ts && ./scripts/compare_screenshots.sh",
"test:visual:accept": "node scripts/accept_visual_regression.js",
diff --git a/src/lib/output/themes/default/DefaultThemeRenderContext.ts b/src/lib/output/themes/default/DefaultThemeRenderContext.ts
index f257ff436..03a52c3b0 100644
--- a/src/lib/output/themes/default/DefaultThemeRenderContext.ts
+++ b/src/lib/output/themes/default/DefaultThemeRenderContext.ts
@@ -39,6 +39,7 @@ import {
sidebarLinks,
} from "./partials/navigation";
import { parameter } from "./partials/parameter";
+import { reflectionPreview } from "./partials/reflectionPreview";
import { toolbar } from "./partials/toolbar";
import { type } from "./partials/type";
import { typeAndParent } from "./partials/typeAndParent";
@@ -117,6 +118,16 @@ export class DefaultThemeRenderContext {
indexTemplate = bind(indexTemplate, this);
defaultLayout = bind(defaultLayout, this);
+ /**
+ * Rendered just after the description for a reflection.
+ * This can be used to render a shortened type display of a reflection that the
+ * rest of the page expands on.
+ *
+ * Note: Will not be called for variables/type aliases, as they are summarized
+ * by their type declaration, which is already rendered by {@link DefaultThemeRenderContext.memberDeclaration}
+ */
+ reflectionPreview = bind(reflectionPreview, this);
+
analytics = bind(analytics, this);
breadcrumb = bind(breadcrumb, this);
commentSummary = bind(commentSummary, this);
diff --git a/src/lib/output/themes/default/partials/member.signatures.tsx b/src/lib/output/themes/default/partials/member.signatures.tsx
index 4fb78bf23..d4e39cefe 100644
--- a/src/lib/output/themes/default/partials/member.signatures.tsx
+++ b/src/lib/output/themes/default/partials/member.signatures.tsx
@@ -9,7 +9,8 @@ export const memberSignatures = (context: DefaultThemeRenderContext, props: Decl
{props.signatures?.map((item) => (
<>
- -
+
-
+
{context.memberSignatureTitle(item)}
{anchorIcon(context, item.anchor)}
diff --git a/src/lib/output/themes/default/partials/reflectionPreview.tsx b/src/lib/output/themes/default/partials/reflectionPreview.tsx
new file mode 100644
index 000000000..3b5630578
--- /dev/null
+++ b/src/lib/output/themes/default/partials/reflectionPreview.tsx
@@ -0,0 +1,20 @@
+import { DeclarationReflection, ReflectionKind, type Reflection, ReflectionType } from "../../../../models";
+import { JSX } from "../../../../utils";
+import { getKindClass } from "../../lib";
+import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext";
+
+export function reflectionPreview(context: DefaultThemeRenderContext, props: Reflection) {
+ if (!(props instanceof DeclarationReflection)) return;
+
+ // Each property of the interface will have a member rendered later on the page describing it, so generate
+ // a type-like object with links to each member.
+ if (props.kindOf(ReflectionKind.Interface)) {
+ return (
+
+ interface
+ {props.name}
+ {context.type(new ReflectionType(props), { topLevelLinks: true })}
+
+ );
+ }
+}
diff --git a/src/lib/output/themes/default/partials/type.tsx b/src/lib/output/themes/default/partials/type.tsx
index c89fef34a..9794c44a8 100644
--- a/src/lib/output/themes/default/partials/type.tsx
+++ b/src/lib/output/themes/default/partials/type.tsx
@@ -86,7 +86,11 @@ export function validateStateIsClean(page: string) {
// 1 | 2[] !== (1 | 2)[]
// () => 1 | 2 !== (() => 1) | 2
const typeRenderers: {
- [K in keyof TypeKindMap]: (context: DefaultThemeRenderContext, type: TypeKindMap[K]) => JSX.Element;
+ [K in keyof TypeKindMap]: (
+ context: DefaultThemeRenderContext,
+ type: TypeKindMap[K],
+ options: { topLevelLinks: boolean },
+ ) => JSX.Element;
} = {
array(context, type) {
return (
@@ -100,7 +104,7 @@ const typeRenderers: {
indentationDepth++;
const parts: JSX.Element[] = [
renderType(context, type.checkType, TypeContext.conditionalCheck),
- extends ,
+ extends ,
renderType(context, type.extendsType, TypeContext.conditionalExtends),
,
includeIndentation(),
@@ -142,11 +146,11 @@ const typeRenderers: {
inferred(context, type) {
return (
<>
- infer {" "}
+ infer {" "}
{type.name}
{type.constraint && (
<>
- extends
+ extends
{renderType(context, type.constraint, TypeContext.inferredConstraint)}
>
)}
@@ -170,23 +174,28 @@ const typeRenderers: {
switch (type.readonlyModifier) {
case "+":
- parts.push(readonly );
+ parts.push(readonly );
break;
case "-":
- parts.push(-readonly );
+ parts.push(
+ <>
+ -
+ readonly
+ >,
+ );
break;
}
parts.push(
[,
{type.parameter},
- in ,
+ in ,
renderType(context, type.parameterType, TypeContext.mappedParameter),
);
if (type.nameType) {
parts.push(
- as ,
+ as ,
renderType(context, type.nameType, TypeContext.mappedName),
);
}
@@ -241,11 +250,11 @@ const typeRenderers: {
predicate(context, type) {
return (
<>
- {!!type.asserts && asserts }
+ {!!type.asserts && asserts }
{type.name}
{!!type.targetType && (
<>
- is
+ is
{renderType(context, type.targetType, TypeContext.predicateTarget)}
>
)}
@@ -255,7 +264,7 @@ const typeRenderers: {
query(context, type) {
return (
<>
- typeof
+ typeof
{renderType(context, type.queryType, TypeContext.queryTypeTarget)}
>
);
@@ -299,17 +308,26 @@ const typeRenderers: {
return name;
},
- reflection(context, type) {
+ reflection(context, type, { topLevelLinks }) {
const members: JSX.Element[] = [];
const children: DeclarationReflection[] = type.declaration.children || [];
indentationDepth++;
+ const renderName = (named: Reflection) =>
+ topLevelLinks ? (
+
+ {named.name}
+
+ ) : (
+ {named.name}
+ );
+
for (const item of children) {
if (item.getSignature && item.setSignature) {
members.push(
<>
- {item.name}
+ {renderName(item)}
:
{renderType(context, item.getSignature.type, TypeContext.none)}
>,
@@ -320,8 +338,8 @@ const typeRenderers: {
if (item.getSignature) {
members.push(
<>
- get
- {item.name}
+ get
+ {renderName(item.getSignature)}
():
{renderType(context, item.getSignature.type, TypeContext.none)}
>,
@@ -332,8 +350,8 @@ const typeRenderers: {
if (item.setSignature) {
members.push(
<>
- set
- {item.name}
+ set
+ {renderName(item.setSignature)}
(
{item.setSignature.parameters?.map((item) => (
<>
@@ -352,11 +370,11 @@ const typeRenderers: {
for (const sig of item.signatures) {
members.push(
<>
- {item.name}
+ {renderName(sig)}
{item.flags.isOptional && ?}
{context.memberSignatureTitle(sig, {
hideName: true,
- arrowStyle: true,
+ arrowStyle: false,
})}
>,
);
@@ -366,7 +384,7 @@ const typeRenderers: {
members.push(
<>
- {item.name}
+ {renderName(item)}
{item.flags.isOptional ? "?: " : ": "}
{renderType(context, item.type, TypeContext.none)}
>,
@@ -468,7 +486,7 @@ const typeRenderers: {
typeOperator(context, type) {
return (
<>
- {type.operator}
+ {type.operator}
{renderType(context, type.target, TypeContext.typeOperatorTarget)}
>
);
@@ -483,13 +501,18 @@ const typeRenderers: {
},
};
-function renderType(context: DefaultThemeRenderContext, type: Type | undefined, where: TypeContext) {
+function renderType(
+ context: DefaultThemeRenderContext,
+ type: Type | undefined,
+ where: TypeContext,
+ options: { topLevelLinks: boolean } = { topLevelLinks: false },
+) {
if (!type) {
return any;
}
const renderFn = typeRenderers[type.type];
- const rendered = renderFn(context, type as never);
+ const rendered = renderFn(context, type as never, options);
if (type.needsParenthesis(where)) {
return (
@@ -504,6 +527,10 @@ function renderType(context: DefaultThemeRenderContext, type: Type | undefined,
return rendered;
}
-export function type(context: DefaultThemeRenderContext, type: Type | undefined) {
- return renderType(context, type, TypeContext.none);
+export function type(
+ context: DefaultThemeRenderContext,
+ type: Type | undefined,
+ options: { topLevelLinks: boolean } = { topLevelLinks: false },
+) {
+ return renderType(context, type, TypeContext.none, options);
}
diff --git a/src/lib/output/themes/default/templates/reflection.tsx b/src/lib/output/themes/default/templates/reflection.tsx
index 503dda2a2..7c5a8f512 100644
--- a/src/lib/output/themes/default/templates/reflection.tsx
+++ b/src/lib/output/themes/default/templates/reflection.tsx
@@ -6,7 +6,7 @@ import { JSX, Raw } from "../../../../utils";
export function reflectionTemplate(context: DefaultThemeRenderContext, props: PageEvent) {
if (
- [ReflectionKind.TypeAlias, ReflectionKind.Variable].includes(props.model.kind) &&
+ props.model.kindOf(ReflectionKind.TypeAlias | ReflectionKind.Variable) &&
props.model instanceof DeclarationReflection
) {
return context.memberDeclaration(props.model);
@@ -20,7 +20,6 @@ export function reflectionTemplate(context: DefaultThemeRenderContext, props: Pa
{context.commentTags(props.model)}
)}
-
{props.model instanceof DeclarationReflection &&
props.model.kind === ReflectionKind.Module &&
props.model.readme?.length && (
@@ -29,6 +28,8 @@ export function reflectionTemplate(context: DefaultThemeRenderContext, props: Pa
)}
+ {context.reflectionPreview(props.model)}
+
{hasTypeParameters(props.model) && <> {context.typeParameters(props.model.typeParameters)} >}
{props.model instanceof DeclarationReflection && (
<>
diff --git a/static/style.css b/static/style.css
index 108428c3f..07a385b73 100644
--- a/static/style.css
+++ b/static/style.css
@@ -11,6 +11,7 @@
--light-color-text-aside: #6e6e6e;
--light-color-link: #1f70c2;
+ --light-color-ts-keyword: #056bd6;
--light-color-ts-project: #b111c9;
--light-color-ts-module: var(--light-color-ts-project);
--light-color-ts-namespace: var(--light-color-ts-project);
@@ -50,6 +51,7 @@
--dark-color-text-aside: #dddddd;
--dark-color-link: #00aff4;
+ --dark-color-ts-keyword: #3399ff;
--dark-color-ts-project: #e358ff;
--dark-color-ts-module: var(--dark-color-ts-project);
--dark-color-ts-namespace: var(--dark-color-ts-project);
@@ -91,6 +93,7 @@
--color-text-aside: var(--light-color-text-aside);
--color-link: var(--light-color-link);
+ --color-ts-keyword: var(--light-color-ts-keyword);
--color-ts-module: var(--light-color-ts-module);
--color-ts-namespace: var(--light-color-ts-namespace);
--color-ts-enum: var(--light-color-ts-enum);
@@ -132,6 +135,7 @@
--color-text-aside: var(--dark-color-text-aside);
--color-link: var(--dark-color-link);
+ --color-ts-keyword: var(--dark-color-ts-keyword);
--color-ts-module: var(--dark-color-ts-module);
--color-ts-namespace: var(--dark-color-ts-namespace);
--color-ts-enum: var(--dark-color-ts-enum);
@@ -180,6 +184,7 @@ body {
--color-text-aside: var(--light-color-text-aside);
--color-link: var(--light-color-link);
+ --color-ts-keyword: var(--light-color-ts-keyword);
--color-ts-module: var(--light-color-ts-module);
--color-ts-namespace: var(--light-color-ts-namespace);
--color-ts-enum: var(--light-color-ts-enum);
@@ -219,6 +224,7 @@ body {
--color-text-aside: var(--dark-color-text-aside);
--color-link: var(--dark-color-link);
+ --color-ts-keyword: var(--dark-color-ts-keyword);
--color-ts-module: var(--dark-color-ts-module);
--color-ts-namespace: var(--dark-color-ts-namespace);
--color-ts-enum: var(--dark-color-ts-enum);
@@ -984,6 +990,11 @@ a.tsd-index-link {
overflow-x: auto;
}
+.tsd-signature-keyword {
+ color: var(--color-ts-keyword);
+ font-weight: normal;
+}
+
.tsd-signature-symbol {
color: var(--color-text-aside);
font-weight: normal;