diff --git a/TODO.md b/TODO.md index a799e22..21dc34d 100644 --- a/TODO.md +++ b/TODO.md @@ -30,8 +30,10 @@ declares one. `dateTimeOriginal()`, `offsetTimeOriginal()`, `exposureTime()`, `fNumber()`, `iso()`, `focalLength()`, `orientation()`, `gpsLatitude()`, `gpsLongitude()` and `gpsAltitude()` (issue 148). Each calls `exif()` and returns its one - field, or undefined when the file lacks it. A test checks, on the JPEG and the - HEIC, that every field `exif()` returns has a method giving the same value. + field, or undefined when the file lacks it. `Photo` implements a type with one + method per `PhotoExif` field, so the build's type check fails when a field has + no method. A test checks, on the JPEG and the HEIC, that each method gives the + same value as `exif()`. - 2026-10-01: `photo.exif()` and `backup-metadata --exif` read EXIF from HEIC/HEIF originals, a live photo's HEIC image included, as well as JPEG and diff --git a/src/library/read.ts b/src/library/read.ts index c2d8203..8af2165 100644 --- a/src/library/read.ts +++ b/src/library/read.ts @@ -35,9 +35,16 @@ const byNewest = (a: PhotoRecord, b: PhotoRecord): number => const byNewestAlbum = (a: AlbumRecord, b: AlbumRecord): number => b.updationTime - a.updationTime || b.collectionID - a.collectionID; +// A method for each `PhotoExif` field, named after it, taking the options +// `exif()` takes and giving that field. `Photo` implements it, so the build's +// type check fails when `PhotoExif` has a field `Photo` has no method for. +type PhotoExifMethods = { + [K in keyof PhotoExif]-?: (opts?: ContentOptions) => Promise; +}; + // A single photo. Field access mirrors `PhotoRecord`; `record()` returns the // underlying plain record for callers that need the IPC-safe value. -export class Photo { +export class Photo implements PhotoExifMethods { constructor( private readonly rec: PhotoRecord, private readonly cache?: PhotoContent, diff --git a/test/library/content-library.test.ts b/test/library/content-library.test.ts index 7864483..7485ade 100644 --- a/test/library/content-library.test.ts +++ b/test/library/content-library.test.ts @@ -462,6 +462,10 @@ describe("Photo save path, local copy, content and EXIF", () => { await lib.close(); }); + // The build's type check, not this test, makes sure `Photo` has a method + // for every `PhotoExif` field, whatever the fixtures hold: `Photo` + // implements a type with one method per field. This test checks that each + // method gives the same value as exif(). it.each([ ["JPEG", JPEG_WITH_EXIF], ["HEIC", HEIC_WITH_EXIF],