Skip to content

Commit e97334e

Browse files
fix: crash in getWellKnownSymbolPropertyOfType for mapped typeof symbol (#698)
<!-- 👋 Hi, thanks for sending a PR to ts-api-utils! 💖. Please fill out all fields below and make sure each item is true and [x] checked. Otherwise we may not be able to review your PR. --> ## PR Checklist - [x] Addresses an existing open issue: fixes typescript-eslint/typescript-eslint#10747 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/ts-api-utils/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/ts-api-utils/blob/main/.github/CONTRIBUTING.md) were taken ## Overview As seen in typescript-eslint/typescript-eslint#10747, we can't assume that prop's declarations array can be found. If the type being checked is a mapped type over the requested well-known symbol, it'll come up as `undefined`. 💖
1 parent d0ae2cb commit e97334e

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/types/getters.test.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe("getWellKnownSymbolPropertyOfType", () => {
109109
const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(`
110110
declare const x: {
111111
[Symbol.asyncIterator](): AsyncIterator<any>;
112-
}>
112+
};
113113
`);
114114

115115
const node = (sourceFile.statements[0] as ts.VariableStatement)
@@ -143,4 +143,40 @@ describe("getWellKnownSymbolPropertyOfType", () => {
143143
name: /^__@asyncIterator/,
144144
});
145145
});
146+
147+
it("returns undefined when the type maps over typeof the requested symbol", () => {
148+
const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(`
149+
type MapsOverTypeofSymbolIterator = {
150+
[K in typeof Symbol.iterator]: string;
151+
};
152+
153+
declare const hoverStyles: MapsOverTypeofSymbolIterator;
154+
155+
const testObject = { ...hoverStyles };
156+
`);
157+
158+
const node = (sourceFile.statements.at(-1) as ts.VariableStatement)
159+
.declarationList.declarations[0];
160+
161+
const type = typeChecker.getTypeAtLocation(node);
162+
163+
expect(
164+
getWellKnownSymbolPropertyOfType(type, "iterator", typeChecker),
165+
).toBe(undefined);
166+
});
167+
168+
it("returns undefined when given an error type", () => {
169+
const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(`
170+
declare const x: invalid;
171+
`);
172+
173+
const node = (sourceFile.statements[0] as ts.VariableStatement)
174+
.declarationList.declarations[0].name;
175+
176+
const type = typeChecker.getTypeAtLocation(node);
177+
178+
expect(
179+
getWellKnownSymbolPropertyOfType(type, "asyncIterator", typeChecker),
180+
).toBe(undefined);
181+
});
146182
});

src/types/getters.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ export function getWellKnownSymbolPropertyOfType(
9797
continue;
9898
}
9999

100-
const declaration = prop.valueDeclaration ?? prop.getDeclarations()![0];
100+
const declaration = prop.valueDeclaration ?? prop.getDeclarations()?.[0];
101101
if (
102+
!declaration ||
102103
!isNamedDeclarationWithName(declaration) ||
103104
declaration.name === undefined ||
104105
!ts.isComputedPropertyName(declaration.name)

0 commit comments

Comments
 (0)