/** * Type compatibility tests for Metadata and ResolvedMetadata. * * These tests verify that ResolvedMetadata properties can be assigned to * Metadata input types. This is important because users often want to * extend parent metadata in generateMetadata: * * ```ts * export async function generateMetadata(_, parent: ResolvingMetadata) { * const resolved = await parent * return { * openGraph: { * ...resolved.openGraph, // Should not cause type errors * title: 'Override title', * }, * } * } * ``` * * If these tests fail, it means ResolvedMetadata has properties * that are not assignable to Metadata (e.g., `null` vs `undefined` mismatch). */ import type { Metadata, ResolvedMetadata } from 'next' import { expectTypeOf } from 'expect-type' // Extract property types for comparison type ResolvedOpenGraphUrl = NonNullable['url'] type MetadataOpenGraphUrl = NonNullable['url'] type ResolvedTwitterSite = NonNullable['site'] type MetadataTwitterSite = NonNullable['site'] type ResolvedTwitterCreator = NonNullable< ResolvedMetadata['twitter'] >['creator'] type MetadataTwitterCreator = NonNullable['creator'] type ResolvedTwitterSiteId = NonNullable['siteId'] type MetadataTwitterSiteId = NonNullable['siteId'] type ResolvedTwitterCreatorId = NonNullable< ResolvedMetadata['twitter'] >['creatorId'] type MetadataTwitterCreatorId = NonNullable['creatorId'] type ResolvedTwitterDescription = NonNullable< ResolvedMetadata['twitter'] >['description'] type MetadataTwitterDescription = NonNullable< Metadata['twitter'] >['description'] type ResolvedFacebookType = NonNullable type MetadataFacebookType = NonNullable type ResolvedPinterestType = NonNullable type MetadataPinterestType = NonNullable describe('Metadata and ResolvedMetadata type compatibility', () => { describe('top-level ResolvedMetadata', () => { it('should have ResolvedMetadata assignable to Metadata', () => { // This tests spreading the entire resolved metadata: { ...parentMeta, title: 'Test' } expectTypeOf().toMatchTypeOf() }) }) describe('openGraph property types', () => { it('should have ResolvedOpenGraph.url assignable to Metadata.openGraph.url', () => { expectTypeOf().toMatchTypeOf() }) }) describe('twitter property types', () => { it('should have ResolvedTwitter.site assignable to Metadata.twitter.site', () => { expectTypeOf().toMatchTypeOf() }) it('should have ResolvedTwitter.siteId assignable to Metadata.twitter.siteId', () => { expectTypeOf().toMatchTypeOf() }) it('should have ResolvedTwitter.creator assignable to Metadata.twitter.creator', () => { expectTypeOf().toMatchTypeOf() }) it('should have ResolvedTwitter.creatorId assignable to Metadata.twitter.creatorId', () => { expectTypeOf().toMatchTypeOf() }) it('should have ResolvedTwitter.description assignable to Metadata.twitter.description', () => { expectTypeOf().toMatchTypeOf() }) }) describe('facebook property types', () => { it('should have ResolvedFacebook assignable to Metadata.facebook', () => { expectTypeOf().toMatchTypeOf() }) }) describe('pinterest property types', () => { it('should have ResolvedPinterest assignable to Metadata.pinterest', () => { expectTypeOf().toMatchTypeOf() }) }) })