Part of #581.
Motivation
RFC 6265 §5.1.1 defines a specific date parsing algorithm with constraints: year ≥ 1601, day 1–31, hour 0–23, minute 0–59, second 0–59. The parseDate() function implements this algorithm and returns a Date, but nothing distinguishes a Date produced by RFC-compliant cookie date parsing from an arbitrary new Date(). This matters because cookie dates have different validity rules than general-purpose dates.
Current usage
function parseDate(cookieDate: Nullable<string>): Date | undefined
class Cookie {
expires: Date | 'Infinity' | null
setExpires(exp: string | Date): void
}
Nominal type design
declare const tag: unique symbol;
export type CookieExpiryDate = Date & { readonly [tag]: true };
export namespace CookieExpiryDate {
/** Parse a cookie date string per RFC 6265 §5.1.1. */
export function parse(input: string): CookieExpiryDate | undefined {
// Existing parseDate() logic with RFC constraints
}
/** Wrap a known-valid Date (e.g., from Max-Age calculation). */
export function fromDate(date: Date): CookieExpiryDate {
return date as CookieExpiryDate;
}
}
API-compatible refactoring strategy
Return type narrowing (non-breaking)
| Function |
Current return |
New return |
Breaking? |
parseDate() |
Date | undefined |
CookieExpiryDate | undefined |
No — assignable to Date |
Unchanged public surfaces
Cookie.expires remains Date | 'Infinity' | null
Cookie.setExpires() parameter remains string | Date
CreateCookieOptions.expires remains Date | 'Infinity' | null
Internal usage
expiryTime() and TTL() can work with CookieExpiryDate internally
- Distinguishes RFC-parsed dates from arbitrary Date objects in internal logic
Part of #581.
Motivation
RFC 6265 §5.1.1 defines a specific date parsing algorithm with constraints: year ≥ 1601, day 1–31, hour 0–23, minute 0–59, second 0–59. The
parseDate()function implements this algorithm and returns aDate, but nothing distinguishes aDateproduced by RFC-compliant cookie date parsing from an arbitrarynew Date(). This matters because cookie dates have different validity rules than general-purpose dates.Current usage
Nominal type design
API-compatible refactoring strategy
Return type narrowing (non-breaking)
parseDate()Date | undefinedCookieExpiryDate | undefinedDateUnchanged public surfaces
Cookie.expiresremainsDate | 'Infinity' | nullCookie.setExpires()parameter remainsstring | DateCreateCookieOptions.expiresremainsDate | 'Infinity' | nullInternal usage
expiryTime()andTTL()can work withCookieExpiryDateinternally