@@ -188,12 +188,7 @@ module.exports = createRule({
188188 if ( ! utils . isPromiseConstructorLike ( services . program , calleeType ) ) {
189189 return ;
190190 }
191-
192- const nodeToComment = findNodeToComment ( functionDeclaration ) ;
193- if ( ! nodeToComment ) return ;
194191
195- if ( hasJSDocThrowsTag ( sourceCode , nodeToComment ) ) return ;
196-
197192 if ( ! node . arguments . length ) return ;
198193
199194 const firstArg = getFirst ( node . arguments ) ;
@@ -224,7 +219,7 @@ module.exports = createRule({
224219 if ( ! callbackNode ) return ;
225220
226221 /** @type {import('typescript').Type[] } */
227- const rejectTypes = [ ] ;
222+ let rejectTypes = [ ] ;
228223
229224 const isRejectCallbackNameDeclared =
230225 callbackNode . params . length >= 2 ;
@@ -236,7 +231,9 @@ module.exports = createRule({
236231 const callbackScope = sourceCode . getScope ( callbackNode )
237232 if ( ! callbackScope ) return ;
238233
239- const rejectCallbackRefs = callbackScope . set . get ( rejectCallbackNode . name ) ?. references ;
234+ const rejectCallbackRefs =
235+ callbackScope . set . get ( rejectCallbackNode . name ) ?. references ;
236+
240237 if ( ! rejectCallbackRefs ) return ;
241238
242239 const callRefs = rejectCallbackRefs
@@ -266,13 +263,13 @@ module.exports = createRule({
266263 }
267264 }
268265
269- const throwsTagTypes = getJSDocThrowsTagTypes (
266+ const callbackThrowsTagTypes = getJSDocThrowsTagTypes (
270267 checker ,
271268 services . esTreeNodeToTSNodeMap . get ( callbackNode )
272269 ) ;
273270
274- if ( throwsTagTypes . length ) {
275- rejectTypes . push ( ...throwsTagTypes ) ;
271+ if ( callbackThrowsTagTypes . length ) {
272+ rejectTypes . push ( ...callbackThrowsTagTypes ) ;
276273 }
277274
278275 if ( ! rejectTypes . length ) return ;
@@ -291,6 +288,52 @@ module.exports = createRule({
291288
292289 if ( isRejectHandled ) return ;
293290
291+ const nodeToComment = findNodeToComment ( functionDeclaration ) ;
292+ if ( ! nodeToComment ) return ;
293+
294+ if ( hasJSDocThrowsTag ( sourceCode , nodeToComment ) ) {
295+ if ( ! services . esTreeNodeToTSNodeMap . has ( nodeToComment ) ) return ;
296+
297+ const functionDeclarationTSNode = services . esTreeNodeToTSNodeMap . get ( functionDeclaration ) ;
298+
299+ const throwsTags = getJSDocThrowsTags ( functionDeclarationTSNode ) ;
300+ const throwsTagTypeNodes = throwsTags
301+ . map ( tag => tag . typeExpression ?. type )
302+ . filter ( tag => ! ! tag ) ;
303+
304+ if ( ! throwsTagTypeNodes . length ) return ;
305+
306+ // Throws tag with `Promise<...>` considered as a reject tag
307+ const rejectTagTypes = getJSDocThrowsTagTypes ( checker , functionDeclarationTSNode )
308+ . filter ( t =>
309+ utils . isPromiseLike ( services . program , t ) &&
310+ t . symbol . getName ( ) === 'Promise'
311+ )
312+ . map ( t => checker . getAwaitedType ( t ) ?? t )
313+ . flatMap ( t => t . isUnion ( ) ? t . types : t ) ;
314+
315+ const typeGroups = groupTypesByCompatibility (
316+ services . program ,
317+ rejectTypes ,
318+ rejectTagTypes ,
319+ ) ;
320+ if ( ! typeGroups . incompatible ) return ;
321+
322+ const lastTagtypeNode = getLast ( throwsTagTypeNodes ) ;
323+ if ( ! lastTagtypeNode ) return ;
324+
325+ context . report ( {
326+ node,
327+ messageId : 'throwTypeMismatch' ,
328+ fix ( fixer ) {
329+ return fixer . replaceTextRange (
330+ [ lastTagtypeNode . pos , lastTagtypeNode . end ] ,
331+ `Promise<${ typesToUnionString ( checker , rejectTypes ) } >` ,
332+ ) ;
333+ } ,
334+ } ) ;
335+ return ;
336+ }
294337 context . report ( {
295338 node,
296339 messageId : 'missingThrowsTag' ,
0 commit comments