diff --git a/src/nodes/typeGuards/compound.ts b/src/nodes/typeGuards/compound.ts index 5a4adb27..7784df56 100644 --- a/src/nodes/typeGuards/compound.ts +++ b/src/nodes/typeGuards/compound.ts @@ -63,7 +63,7 @@ export function isJsxTagNamePropertyAccess( } export interface NamedDeclarationWithName extends ts.NamedDeclaration { - name: NonNullable; + name: ts.DeclarationName; } export function isNamedDeclarationWithName( diff --git a/src/test/utils.ts b/src/test/utils.ts index e0e8c0fa..0fb1e2b0 100644 --- a/src/test/utils.ts +++ b/src/test/utils.ts @@ -29,7 +29,7 @@ export function createSourceFileAndTypeChecker( sourceText: string, fileName = "file.ts" ): SourceFileAndTypeChecker { - const compilerOptions = {}; + const compilerOptions = { target: ts.ScriptTarget.ES2018 }; const fsMap = tsvfs .createDefaultMapFromNodeModules(compilerOptions) .set(fileName, sourceText); diff --git a/src/types/getters.test.ts b/src/types/getters.test.ts new file mode 100644 index 00000000..36eaa4ab --- /dev/null +++ b/src/types/getters.test.ts @@ -0,0 +1,27 @@ +import * as ts from "typescript"; +import { describe, expect, it } from "vitest"; + +import { createSourceFileAndTypeChecker } from "../test/utils.js"; +import { getWellKnownSymbolPropertyOfType } from "./getters.js"; + +describe("getWellKnownSymbolPropertyOfType", () => { + // /~https://github.com/JoshuaKGoldberg/ts-api-tools/issues/15 + it("gets the property when it does not have a value declaration", () => { + const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(` + declare const x: Omit<{ + [Symbol.asyncIterator](): AsyncIterator; + }, 'z'> + `); + + const node = (sourceFile.statements[0] as ts.VariableStatement) + .declarationList.declarations[0].name; + + const type = typeChecker.getTypeAtLocation(node); + + expect( + getWellKnownSymbolPropertyOfType(type, "asyncIterator", typeChecker) + ).toMatchObject({ + name: /^__@asyncIterator/, + }); + }); +}); diff --git a/src/types/getters.ts b/src/types/getters.ts index 29db9479..2fe07495 100644 --- a/src/types/getters.ts +++ b/src/types/getters.ts @@ -3,6 +3,7 @@ import * as ts from "typescript"; +import { isNamedDeclarationWithName } from "../nodes/typeGuards/index.js"; import { isIntersectionType, isUnionType, @@ -50,15 +51,21 @@ export function getWellKnownSymbolPropertyOfType( const prefix = "__@" + wellKnownSymbolName; for (const prop of type.getProperties()) { - if (!prop.name.startsWith(prefix)) continue; + if (!prop.name.startsWith(prefix)) { + continue; + } + + const declaration = prop.valueDeclaration ?? prop.getDeclarations()![0]; + if ( + !isNamedDeclarationWithName(declaration) || + declaration.name === undefined || + !ts.isComputedPropertyName(declaration.name) + ) { + continue; + } const globalSymbol = typeChecker.getApparentType( - typeChecker.getTypeAtLocation( - ( - (prop.valueDeclaration as ts.NamedDeclaration) - .name as ts.ComputedPropertyName - ).expression - ) + typeChecker.getTypeAtLocation(declaration.name.expression) ).symbol; if (