Photo implements one method per PhotoExif field
check / check (push) Successful in 1m46s

Photo now implements a mapped type with one method per PhotoExif field,
each taking exif()'s options and giving that field's type, so the
build's type check fails when PhotoExif has a field Photo has no method
for, whatever the test fixtures hold. The test comment and TODO.md say
so.

Model: opus-5-5
This commit is contained in:
2026-10-01 21:11:05 +00:00
parent b669df220a
commit 4986ebd889
3 changed files with 16 additions and 3 deletions
+4 -2
View File
@@ -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
+8 -1
View File
@@ -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<PhotoExif[K]>;
};
// 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,
+4
View File
@@ -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],