Skip to content

Commit 3748bbe

Browse files
authored
fix(no-undefined-types): check class and interface globals; fixes #1420 (#1421)
1 parent 26276ba commit 3748bbe

File tree

3 files changed

+88
-13
lines changed

3 files changed

+88
-13
lines changed

docs/rules/no-undefined-types.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,5 +971,23 @@ export default [
971971
* @type {Abc['def']}
972972
*/
973973
export const a = 'someString';
974+
975+
export interface SomeInterface {
976+
someProp: unknown;
977+
}
978+
979+
/**
980+
* {@link SomeInterface.someProp}
981+
* @returns something
982+
*/
983+
984+
class SomeClass {
985+
someMethod () {}
986+
}
987+
988+
/**
989+
* {@link SomeClass.someMethod}
990+
* @returns something
991+
*/
974992
````
975993

src/rules/noUndefinedTypes.js

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -269,24 +269,54 @@ export default iterateJsdoc(({
269269
variables,
270270
}) => {
271271
return variables;
272-
}).map(({
272+
}).flatMap(({
273273
identifiers,
274274
name,
275275
}) => {
276-
if (
277-
[
278-
'ImportDefaultSpecifier',
279-
'ImportNamespaceSpecifier',
280-
'ImportSpecifier',
281-
].includes(
282-
/** @type {import('estree').Identifier & {parent: {type: string}}} */ (
283-
identifiers?.[0])?.parent?.type,
284-
)
285-
) {
286-
imports.push(name);
276+
const globalItem = /** @type {import('estree').Identifier & {parent: import('@typescript-eslint/types').TSESTree.Node}} */ (
277+
identifiers?.[0]
278+
)?.parent;
279+
switch (globalItem?.type) {
280+
case 'ClassDeclaration':
281+
return [
282+
name,
283+
...globalItem.body.body.map((item) => {
284+
const property = /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
285+
/** @type {import('@typescript-eslint/types').TSESTree.PropertyDefinition} */ (
286+
item)?.key)?.name;
287+
/* c8 ignore next 3 -- Guard */
288+
if (!property) {
289+
return '';
290+
}
291+
292+
return `${name}.${property}`;
293+
}).filter(Boolean),
294+
];
295+
case 'ImportDefaultSpecifier':
296+
case 'ImportNamespaceSpecifier':
297+
case 'ImportSpecifier':
298+
imports.push(name);
299+
break;
300+
case 'TSInterfaceDeclaration':
301+
return [
302+
name,
303+
...globalItem.body.body.map((item) => {
304+
const property = /** @type {import('@typescript-eslint/types').TSESTree.Identifier} */ (
305+
/** @type {import('@typescript-eslint/types').TSESTree.TSPropertySignature} */ (
306+
item)?.key)?.name;
307+
/* c8 ignore next 3 -- Guard */
308+
if (!property) {
309+
return '';
310+
}
311+
312+
return `${name}.${property}`;
313+
}).filter(Boolean),
314+
];
287315
}
288316

289-
return name;
317+
return [
318+
name,
319+
];
290320
/* c8 ignore next */
291321
}) : [],
292322
)

test/rules/assertions/noUndefinedTypes.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,5 +1692,32 @@ export default /** @type {import('../index.js').TestCases} */ ({
16921692
16931693
`,
16941694
},
1695+
{
1696+
code: `
1697+
export interface SomeInterface {
1698+
someProp: unknown;
1699+
}
1700+
1701+
/**
1702+
* {@link SomeInterface.someProp}
1703+
* @returns something
1704+
*/
1705+
`,
1706+
languageOptions: {
1707+
parser: typescriptEslintParser,
1708+
},
1709+
},
1710+
{
1711+
code: `
1712+
class SomeClass {
1713+
someMethod () {}
1714+
}
1715+
1716+
/**
1717+
* {@link SomeClass.someMethod}
1718+
* @returns something
1719+
*/
1720+
`,
1721+
},
16951722
],
16961723
});

0 commit comments

Comments
 (0)