Skip to content

fix(types): enforce required as attribute for preload links#683

Merged
harlan-zw merged 1 commit into
mainfrom
fix/527-enforce-required-attrs-types
Mar 10, 2026
Merged

fix(types): enforce required as attribute for preload links#683
harlan-zw merged 1 commit into
mainfrom
fix/527-enforce-required-attrs-types

Conversation

@harlan-zw

@harlan-zw harlan-zw commented Mar 10, 2026

Copy link
Copy Markdown
Collaborator

🔗 Linked issue

Resolves #527

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • 🧹 Chore
  • ⚠️ Breaking change

📚 Description

The PreloadLink discriminated union types already required as, but GenericLink (the catch-all with rel: string) absorbed preload objects bypassing the requirement. Added KnownLinkRel type union, BareAlternateLink for real-world alternate usage, and documented the TypeScript limitation where GenericLink absorbs literal rel values. Using PreloadLink directly now correctly enforces as. Also fixed several existing tests that had incorrect preload links missing as or crossorigin.

Summary by CodeRabbit

  • New Features

    • Exported new link types: BareAlternateLink, KnownLinkRel, and PreloadLink for enhanced type safety and flexibility.
  • Refactor

    • Improved internal type handling for link elements with refined type inference.
  • Tests

    • Updated test fixtures to align with enhanced type specifications.

Add `BareAlternateLink` for bare `rel="alternate"` links without hreflang/type/media.
Add `KnownLinkRel` union type enumerating all known rel values.
Update `PreloadLink` subtypes to correctly require `as` when used directly.
Improve `GenericLink` and `Link` JSDoc to clarify the `as`-for-preload enforcement
  through the `PreloadLink` type union.
Add type tests verifying `PreloadLink` rejects missing `as` at compile time.
Fix tests using preload links without `as` (capo) and font preloads without
  `crossorigin` (benchmark) to match correct HTML semantics.
Use `as const` in tests where TypeScript widened rel to `string` (keys, deduping).
Use type assertion in `useScript` warmup for the runtime-conditional link object.

Closes #527
@coderabbitai

coderabbitai Bot commented Mar 10, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 431856e1-6ea1-4e55-9be6-753982afba32

📥 Commits

Reviewing files that changed from the base of the PR and between 4838b84 and 1b5521c.

📒 Files selected for processing (9)
  • packages/unhead/src/scripts/useScript.ts
  • packages/unhead/src/types/schema/head.ts
  • packages/unhead/src/types/schema/link.ts
  • packages/unhead/test/streaming/benchmark.test.ts
  • packages/unhead/test/unit/e2e/deduping.test.ts
  • packages/unhead/test/unit/plugins/capo.test.ts
  • packages/unhead/test/unit/types.test.ts
  • packages/vue/test/unit/e2e/keys.test.ts
  • packages/vue/test/unit/ssr/customAugmentation.test.ts

📝 Walkthrough

Walkthrough

The changes introduce type-level enforcement for conditional link attributes, specifically requiring the as property for preload links through a new PreloadLink type. Support for bare alternate links is added, known link rel values are enumerated, and test cases are updated to validate the new type constraints.

Changes

Cohort / File(s) Summary
Link Type Definitions
packages/unhead/src/types/schema/link.ts, packages/unhead/src/types/schema/head.ts
Added BareAlternateLink interface for alternate links without hreflang/type/media requirements. Introduced KnownLinkRel union type enumerating known link rel values. Updated AlternateLink and Link unions to include BareAlternateLink. Re-exported new types through head.ts.
Hook Implementation
packages/unhead/src/scripts/useScript.ts
Refactored type annotation for warmup link object using inline untyped object with cast to RawInput<'link'> instead of explicit type annotation. Added explanatory comments on runtime guarantees for preload and preconnect/dns-prefetch attributes.
Type Tests
packages/unhead/test/unit/types.test.ts
Introduced new PreloadLink type export that enforces as property requirement for preload links. Added test cases demonstrating valid preload entries with as, valid modulepreload entries without as, and type-level rejection of missing as for PreloadLink.
Link Attribute Tests
packages/unhead/test/unit/e2e/deduping.test.ts, packages/unhead/test/unit/plugins/capo.test.ts
Applied const assertions to rel values (canonical, stylesheet) for stricter type inference. Added as: 'script' attribute to preload link object in capo test.
Benchmark & Vue Tests
packages/unhead/test/streaming/benchmark.test.ts, packages/vue/test/unit/e2e/keys.test.ts, packages/vue/test/unit/ssr/customAugmentation.test.ts
Updated benchmark with crossorigin: 'anonymous' for font preload. Applied const assertion to stylesheet rel value in vue keys test. Simplified customAugmentation test by removing explicit types and using inline as any cast for link items.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With types now strict and bold,
The as won't hide, a story told,
Preload links dance in perfect form,
No missing props to break the norm,
TypeScript safety, strong and true!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately and concisely summarizes the main change: enforcing the required 'as' attribute for preload links through type system improvements.
Description check ✅ Passed Description includes all required template sections: linked issue (#527), type of change (Enhancement), and detailed explanation of changes and rationale.
Linked Issues check ✅ Passed All coding requirements from #527 are met: PreloadLink now enforces the required 'as' attribute through TypeScript types, with proper type union definitions (KnownLinkRel, BareAlternateLink) and type tests demonstrating the enforcement.
Out of Scope Changes check ✅ Passed All changes are directly related to the issue objective: type definitions for link relations, PreloadLink type enforcement, test fixes for missing 'as' attributes, and type-level verification tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/527-enforce-required-attrs-types

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

Bundle Size Gzipped
Client (Minimal) 10.5 kB 4.3 kB
Server (Minimal) 10.2 kB 4.2 kB
Vue Client (Minimal) 11.4 kB 4.7 kB
Vue Server (Minimal) 11.1 kB 4.6 kB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enforce Optionally Required Attributes Through Types

1 participant