/* eslint-disable react/no-array-index-key */
// https://github.com/TypeStrong/typedoc-default-themes/blob/master/src/default/partials/type.hbs
import { Fragment } from 'react';
import type { JSONOutput } from 'typedoc';
import Link from '@docusaurus/Link';
import { useReflectionMap } from '../hooks/useReflectionMap';
import type { TSDDeclarationReflection } from '../types';
import { MemberSignatureTitle } from './MemberSignatureTitle';
export function extractDeclarationFromType(
type?: JSONOutput.Reflection | JSONOutput.SomeType,
): TSDDeclarationReflection | undefined {
if (!type) {
return undefined;
}
return (type as unknown as { declaration?: TSDDeclarationReflection })?.declaration;
}
function parens(element: JSX.Element, needsParens: boolean): JSX.Element {
if (!needsParens) {
return element;
}
return (
<>
{needsParens && (}
{element}
{needsParens && )}
>
);
}
export interface TypeProps {
needsParens?: boolean;
type?: { type: string; value?: unknown };
}
// eslint-disable-next-line complexity
export function Type({ needsParens = false, type: base }: TypeProps) {
const reflections = useReflectionMap();
if (!base) {
return null;
}
// Cast to string since `type` doesnt include all string values in the union.
// https://github.com/TypeStrong/typedoc/blob/master/src/lib/output/themes/default/partials/type.tsx
switch (String(base.type)) {
case 'array': {
const type = base as JSONOutput.ArrayType;
return (
<>
[]
>
);
}
case 'conditional': {
const type = base as JSONOutput.ConditionalType;
return parens(
<>
extends
?
:
>,
needsParens,
);
}
case 'indexedAccess': {
const type = base as JSONOutput.IndexedAccessType;
return (
<>
[
]
>
);
}
case 'inferred': {
const type = base as JSONOutput.InferredType;
return (
<>
infer {type.name}
>
);
}
case 'intersection': {
const type = base as JSONOutput.IntersectionType;
return parens(
<>
{type.types.map((t, i) => (
{i > 0 && & }
))}
>,
needsParens,
);
}
case 'intrinsic': {
const type = base as JSONOutput.IntrinsicType;
return {type.name};
}
case 'literal': {
const type = base as JSONOutput.LiteralType;
return {String(type.value)};
}
case 'mapped': {
const type = base as unknown as JSONOutput.MappedType;
return (
<>
{'{ '}
{type.readonlyModifier === '+' && readonly }
{type.readonlyModifier === '-' && (
-readonly
)}
[
{type.parameter}
in
{type.nameType && (
<>
as
>
)}
]
{type.optionalModifier === '+' && ?: }
{type.optionalModifier === '-' && -?: }
{!type.optionalModifier && : }
{' }'}
>
);
}
case 'optional': {
const type = base as JSONOutput.OptionalType;
return (
<>
?
>
);
}
case 'predicate': {
const type = base as JSONOutput.PredicateType;
return (
<>
{type.asserts && asserts }
{type.name}
{type.targetType && (
<>
is
>
)}
>
);
}
case 'query': {
const type = base as JSONOutput.QueryType;
return (
<>
typeof
>
);
}
case 'reference': {
const type = base as JSONOutput.ReferenceType;
const ref = type.target ? reflections[Number(type.target)] : null;
const genericClass = ref?.id && !ref.sources ? 'tsd-signature-type-generic' : '';
return (
<>
{ref?.permalink ? (
{type.name}
) : (
{type.name}
)}
{type.typeArguments && type.typeArguments.length > 0 && (
<>
<
{type.typeArguments.map((t, i) => (
{i > 0 && , }
))}
>
>
)}
>
);
}
case 'reflection': {
const type = base as JSONOutput.ReflectionType;
const decl = type.declaration;
// object literal
if (decl?.children && decl.children.length > 0) {
return (
<>
{'{ '}
{decl.children.map((child, i) => (
{i > 0 && ; }
{child.name}
{child.flags?.isOptional && '?'}:
{child.type ? : 'any'}
))}
{' }'}
>
);
}
if (decl?.signatures && decl.signatures.length === 1) {
return ;
}
if (decl?.signatures && decl.signatures.length > 0) {
return parens(
<>
{'{ '}
{decl.signatures.map((sig, i) => (
{i > 0 && ; }
))}
{' }'}
>,
needsParens,
);
}
return <>{'{}'}>;
}
case 'rest': {
const type = base as JSONOutput.RestType;
return (
<>
...
>
);
}
case 'tuple': {
const type = base as JSONOutput.TupleType;
return (
<>
[
{type.elements?.map((t, i) => (
{i > 0 && , }
))}
]
>
);
}
case 'typeOperator': {
const type = base as JSONOutput.TypeOperatorType;
return (
<>
{type.operator}
>
);
}
// case 'typeParameter': {
// const type = base as JSONOutput.TypeParameterType;
// return {type.name};
// }
case 'union': {
const type = base as JSONOutput.UnionType;
return parens(
<>
{type.types.map((t, i) => (
{i > 0 && | }
))}
>,
needsParens,
);
}
case 'unknown': {
const type = base as JSONOutput.UnknownType;
return {type.name};
}
case 'named-tuple-member':
case 'namedTupleMember': {
const type = base as unknown as JSONOutput.NamedTupleMemberType;
return (
<>
{type.name}
{type.isOptional ? '?: ' : ': '}
>
);
}
case 'template-literal':
case 'templateLiteral': {
const type = base as unknown as JSONOutput.TemplateLiteralType;
return (
<>
`
{type.head && {type.head}}
{type.tail.map((t, i) => (
{'${'}
{typeof t[0] !== 'string' && }
{'}'}
{typeof t[1] === 'string' && {t[1]}}
))}
`
>
);
}
default:
return void;
}
}