Repository: vercel/next.js
Pull request: [ts-next-plugin] fix: warn only if no type for separate export

### Why?

The "separate export" was not warning correctly. It is because the `symbol.declaration` is a declaration from the export clause. Needed to get from `originalSymbol.declaration`.

| Before | After |
|--------|--------|
| ![CleanShot 2025-04-28 at 22 55 48@2x](https://github.com/user-attachments/assets/696cfb07-e44c-4541-9486-cf62053f5acc) | ![CleanShot 2025-04-28 at 23 04 31@2x](https://github.com/user-attachments/assets/817d99cb-0dd3-4fb8-84ce-5f298b32185c) | 

Changed files:
filename: packages/next/src/server/typescript/rules/metadata.ts
patch: @@ -166,95 +166,93 @@ const metadata = {
             continue
           }
           const exportName = e.name.getText()
-          if (exportName !== 'generateMetadata' && exportName !== 'metadata') {
+          if (exportName !== 'metadata' && exportName !== 'generateMetadata') {
             continue
           }
 
-          // Get the symbol and type for the export
           const symbol = typeChecker.getSymbolAtLocation(e.name)
-          if (!symbol) continue
+          if (!symbol) {
+            continue
+          }
+
+          const originalSymbol = typeChecker.getAliasedSymbol(symbol)
+          const declarations = originalSymbol.getDeclarations()
+          if (!declarations) {
+            continue
+          }
 
-          const type = typeChecker.getTypeOfSymbolAtLocation(symbol, e.name)
-          if (!type) continue
+          const declaration = declarations[0]
+          if (hasType(declaration)) {
+            continue
+          }
 
           if (exportName === 'generateMetadata') {
             let isAsync = false
 
-            // For export declarations, we need to get the actual declaration through the type checker
-            const originalSymbol = typeChecker.getAliasedSymbol(symbol)
-            const declaration = originalSymbol?.declarations?.[0]
+            // async function() {}
+            if (ts.isFunctionDeclaration(declaration)) {
+              isAsync =
+                declaration.modifiers?.some(
+                  (m) => m.kind === ts.SyntaxKind.AsyncKeyword
+                ) ?? false
+            }
 
-            if (declaration) {
-              if (ts.isFunctionDeclaration(declaration)) {
+            // foo = async function() {}
+            // foo = async () => {}
+            if (
+              ts.isVariableDeclaration(declaration) &&
+              declaration.initializer
+            ) {
+              const initializer = declaration.initializer
+              const isFunction =
+                ts.isArrowFunction(initializer) ||
+                ts.isFunctionExpression(initializer)
+
+              if (isFunction) {
                 isAsync =
-                  declaration.modifiers?.some(
+                  initializer.modifiers?.some(
                     (m) => m.kind === ts.SyntaxKind.AsyncKeyword
                   ) ?? false
-              } else if (
-                ts.isVariableDeclaration(declaration) &&
-                declaration.initializer
-              ) {
-                if (
-                  ts.isArrowFunction(declaration.initializer) ||
-                  ts.isFunctionExpression(declaration.initializer)
-                ) {
-                  isAsync =
-                    declaration.initializer.modifiers?.some(
-                      (m) => m.kind === ts.SyntaxKind.AsyncKeyword
-                    ) ?? false
-                }
               }
             }
 
-            if (
-              declaration &&
-              ts.isFunctionDeclaration(declaration) &&
-              !hasType(declaration)
-            ) {
-              diagnostics.push({
-                file: source,
-                category: ts.DiagnosticCategory.Warning,
-                code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
-                messageText: `The "generateMetadata" export should have a return type of ${isAsync ? '"Promise<Metadata>"' : '"Metadata"'} from "next".`,
-                start: e.name.getStart(),
-                length: e.name.getWidth(),
-              })
-            }
+            diagnostics.push({
+              file: source,
+              category: ts.DiagnosticCategory.Warning,
+              code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
+              messageText: `The Next.js "generateMetadata" export should have a return type of ${isAsync ? '"Promise<Metadata>"' : '"Metadata"'} from "next".`,
+              start: e.name.getStart(),
+              length: e.name.getWidth(),
+            })
           } else {
-            // must be 'metadata' at this point
-            const declaration = symbol.declarations?.[0]
-            if (
-              declaration &&
-              ts.isVariableDeclaration(declaration) &&
-              !hasType(declaration)
-            ) {
-              diagnostics.push({
-                file: source,
-                category: ts.DiagnosticCategory.Warning,
-                code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
-                messageText: `The Next.js "metadata" export should be type of "Metadata" from "next".`,
-                start: e.name.getStart(),
-                length: e.name.getWidth(),
-              })
-            }
+            diagnostics.push({
+              file: source,
+              category: ts.DiagnosticCategory.Warning,
+              code: NEXT_TS_ERRORS.INVALID_METADATA_EXPORT,
+              messageText: `The Next.js "metadata" export should be type of "Metadata" from "next".`,
+              start: e.name.getStart(),
+              length: e.name.getWidth(),
+            })
           }
         }
       }
-
       return diagnostics
     },
   },
 }
 
-function hasType(
-  node:
-    | tsModule.FunctionDeclaration
-    | tsModule.VariableDeclaration
-    | tsModule.FunctionExpression
-    | tsModule.ArrowFunction
-): boolean {
+function hasType(node: tsModule.Declaration): boolean {
   const ts = getTs()
 
+  if (
+    !ts.isVariableDeclaration(node) &&
+    !ts.isFunctionDeclaration(node) &&
+    !ts.isArrowFunction(node) &&
+    !ts.isFunctionExpression(node)
+  ) {
+    return false
+  }
+
   // For function declarations, expressions, and arrow functions, check if they have return type
   if (
     ts.isFunctionDeclaration(node) ||