I centralised this site's identity into one lib/site.ts so the canonical domain would stop being duplicated across layout, sitemap and robots. First instinct: mark the object as const so every string keeps its literal type.

It broke the moment the object had to satisfy Metadata:

export const SITE = {
  socials: [{ label: "LinkedIn", href: "https://…" }],
} as const;
 
// Type 'readonly ["https://…"]' is not assignable to type 'string[]'.
socialUrls: SITE.socials.map((s) => s.href)

as const doesn't just narrow the values — it deep-freezes them into readonly tuples. Metadata["keywords"] wants string[], and a readonly string[] is not one.

The fix was to keep the literal types on the individual strings I actually wanted narrowed and drop the outer assertion. You get the same editor completion without the readonly contagion spreading into every consumer.

Worth remembering the general shape: as const inference propagates outward to whoever receives the value, not just the declaration it's written on.