diff --git a/package.json b/package.json index 66ffc5465..4598454e9 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@types/jest": "^29.5.12", "@types/node": "^20.12.7", "@types/normalize-path": "^3.0.2", + "@types/ts-expose-internals": "npm:ts-expose-internals@^5.4.5", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "auto": "^11.1.6", diff --git a/src/NodeParser/FunctionNodeParser.ts b/src/NodeParser/FunctionNodeParser.ts index d75003824..1426c44fb 100644 --- a/src/NodeParser/FunctionNodeParser.ts +++ b/src/NodeParser/FunctionNodeParser.ts @@ -16,12 +16,7 @@ export class FunctionNodeParser implements SubNodeParser { ) {} public supportsNode(node: ts.TypeNode): boolean { - return ( - node.kind === ts.SyntaxKind.FunctionType || - node.kind === ts.SyntaxKind.FunctionExpression || - node.kind === ts.SyntaxKind.ArrowFunction || - node.kind === ts.SyntaxKind.FunctionDeclaration - ); + return node.kind === ts.SyntaxKind.FunctionType; } public createType( diff --git a/src/NodeParser/PromiseNodeParser.ts b/src/NodeParser/PromiseNodeParser.ts index 2259730a9..016c9811c 100644 --- a/src/NodeParser/PromiseNodeParser.ts +++ b/src/NodeParser/PromiseNodeParser.ts @@ -1,5 +1,5 @@ import ts from "typescript"; -import type { Context, NodeParser } from "../NodeParser.js"; +import { Context, NodeParser } from "../NodeParser.js"; import type { SubNodeParser } from "../SubNodeParser.js"; import { AliasType } from "../Type/AliasType.js"; import type { BaseType } from "../Type/BaseType.js"; @@ -31,13 +31,24 @@ export class PromiseNodeParser implements SubNodeParser { const type = this.typeChecker.getTypeAtLocation(node); - // @ts-expect-error - Internal API of TypeScript const awaitedType = this.typeChecker.getAwaitedType(type); + // ignores non awaitable types + if (!awaitedType) { + return false; + } + // If the awaited type differs from the original type, the type extends promise // Awaited> -> T (Promise !== T) // Awaited -> Y (Y === Y) - return awaitedType !== type && !this.typeChecker.isTypeAssignableTo(type, awaitedType); + if (awaitedType === type) { + return false; + } + + // In types like: A = T, type C = A<1>, C has the same type as A<1> and 1, + // the awaitedType is NOT the same reference as the type, so a assignability + // check is needed + return !this.typeChecker.isTypeAssignableTo(type, awaitedType); } public createType( @@ -45,11 +56,8 @@ export class PromiseNodeParser implements SubNodeParser { context: Context, ): BaseType { const type = this.typeChecker.getTypeAtLocation(node); - - // @ts-expect-error - Internal API of TypeScript - const awaitedType = this.typeChecker.getAwaitedType(type); - - const awaitedNode = this.typeChecker.typeToTypeNode(awaitedType, undefined, ts.NodeBuilderFlags.NoTruncation); + const awaitedType = this.typeChecker.getAwaitedType(type)!; // supportsNode ensures this + const awaitedNode = this.typeChecker.typeToTypeNode(awaitedType, undefined, ts.NodeBuilderFlags.IgnoreErrors); if (!awaitedNode) { throw new Error( @@ -57,7 +65,7 @@ export class PromiseNodeParser implements SubNodeParser { ); } - const baseNode = this.childNodeParser.createType(awaitedNode, context); + const baseNode = this.childNodeParser.createType(awaitedNode, new Context(node)); const name = this.getNodeName(node); diff --git a/yarn.lock b/yarn.lock index 5cb315869..3445f2337 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1971,6 +1971,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== +"@types/ts-expose-internals@npm:ts-expose-internals@^5.4.5": + version "5.4.5" + resolved "https://registry.yarnpkg.com/ts-expose-internals/-/ts-expose-internals-5.4.5.tgz#94da2b665627135ad1281d98af3ccb08cb4c1950" + integrity sha512-0HfRwjgSIOyuDlHzkFedMWU4aHWq9pu4MUKHgH75U+L76wCAtK5WB0rc/dAIhulMRcPUlcKONeiiR5Sxy/7XcA== + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15"