Skip to content

Commit 4605d89

Browse files
Use a mapped type to enforce type-safety on forEachChild. (#50409)
1 parent 6362fb2 commit 4605d89

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

src/compiler/parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ namespace ts {
9696
}
9797

9898
type ForEachChildFunction<TNode> = <T>(node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined) => T | undefined;
99-
const forEachChildTable = {
99+
type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction<TNode> };
100+
const forEachChildTable: ForEachChildTable = {
100101
[SyntaxKind.QualifiedName]: function forEachChildInQualifiedName<T>(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
101102
return visitNode(cbNode, node.left) ||
102103
visitNode(cbNode, node.right);

src/compiler/types.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -885,9 +885,59 @@ namespace ts {
885885
/* @internal */ jsDocCache?: readonly JSDocTag[]; // Cache for getJSDocTags
886886
}
887887

888+
// Ideally, `ForEachChildNodes` and `VisitEachChildNodes` would not differ.
889+
// However, `forEachChild` currently processes JSDoc comment syntax and missing declarations more thoroughly.
890+
// On the other hand, `visitEachChild` actually processes `Identifier`s (which really *shouldn't* have children,
891+
// but are constructed as if they could for faked-up `QualifiedName`s in the language service.)
892+
888893
/* @internal */
889-
export type HasChildren =
894+
export type ForEachChildNodes =
895+
| HasChildren
896+
| MissingDeclaration
897+
| JSDocTypeExpression
898+
| JSDocNonNullableType
899+
| JSDocNullableType
900+
| JSDocOptionalType
901+
| JSDocVariadicType
902+
| JSDocFunctionType
903+
| JSDoc
904+
| JSDocSeeTag
905+
| JSDocNameReference
906+
| JSDocMemberName
907+
| JSDocParameterTag
908+
| JSDocPropertyTag
909+
| JSDocAuthorTag
910+
| JSDocImplementsTag
911+
| JSDocAugmentsTag
912+
| JSDocTemplateTag
913+
| JSDocTypedefTag
914+
| JSDocCallbackTag
915+
| JSDocReturnTag
916+
| JSDocTypeTag
917+
| JSDocThisTag
918+
| JSDocEnumTag
919+
| JSDocSignature
920+
| JSDocLink
921+
| JSDocLinkCode
922+
| JSDocLinkPlain
923+
| JSDocTypeLiteral
924+
| JSDocUnknownTag
925+
| JSDocClassTag
926+
| JSDocPublicTag
927+
| JSDocPrivateTag
928+
| JSDocProtectedTag
929+
| JSDocReadonlyTag
930+
| JSDocDeprecatedTag
931+
;
932+
933+
/* @internal */
934+
export type VisitEachChildNodes =
935+
| HasChildren
890936
| Identifier
937+
;
938+
939+
/* @internal */
940+
export type HasChildren =
891941
| QualifiedName
892942
| ComputedPropertyName
893943
| TypeParameterDeclaration

src/compiler/visitorPublic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ namespace ts {
403403
// }
404404
//
405405
// This is then used as the expected type for `visitEachChildTable`.
406-
type VisitEachChildTable = { [TNode in HasChildren as TNode["kind"]]: VisitEachChildFunction<TNode> };
406+
type VisitEachChildTable = { [TNode in VisitEachChildNodes as TNode["kind"]]: VisitEachChildFunction<TNode> };
407407

408408
// NOTE: Before you can add a new method to `visitEachChildTable`, you must first ensure the `Node` subtype you
409409
// wish to add is defined in the `HasChildren` union in types.ts.

0 commit comments

Comments
 (0)