fix(web): resolve all 22 TypeScript typecheck errors in apps/web (TEC-3208)

- Fix TS4111: use bracket notation for index signature access in metadata.spec.ts,
  neighborhood-poi-map.tsx, and neighborhood-poi-map.spec.tsx
- Fix TS2740: add missing property fields (usableAreaM2, floor, totalFloors,
  nearbyPOIs, etc.) to test mock objects in 5 spec files
- Fix TS2339: add missing estimate() and create() methods to transferApi
- Fix TS4114: add override modifier to render() in page.tsx error boundary
- Fix TS2532: add optional chaining for possibly undefined features in
  neighborhood-poi-map.tsx

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-22 15:49:38 +07:00
parent 566ad75c0e
commit 1668c800fe
10 changed files with 97 additions and 14 deletions

View File

@@ -102,6 +102,20 @@ function makeListing(id: string, overrides: Partial<ListingDetail> = {}): Listin
latitude: null,
longitude: null,
media: [{ id: 'm1', type: 'image', url: 'https://example.com/img.jpg', order: 0, caption: null }],
usableAreaM2: null,
floor: null,
totalFloors: null,
nearbyPOIs: null,
metroDistanceM: null,
furnishing: null,
propertyCondition: null,
balconyDirection: null,
maintenanceFeeVND: null,
parkingSlots: null,
viewType: [],
petFriendly: null,
suitableFor: [],
whyThisLocation: null,
},
seller: { id: 's1', fullName: 'Seller', phone: '0901234567' },
agent: null,

View File

@@ -228,7 +228,7 @@ describe('NeighborhoodPOIMap', () => {
expect(capturedData).not.toBeNull();
expect(capturedData!.features).toHaveLength(2);
expect(capturedData!.features.map((f) => f.properties?.category)).not.toContain('school');
expect(capturedData!.features.map((f) => f.properties?.['category'])).not.toContain('school');
});
// ── Loading state ─────────────────────────────────────────────────────────────

View File

@@ -264,12 +264,12 @@ export function NeighborhoodPOIMap({
map.on('click', LAYER_CLUSTERS, (e) => {
const features = map.queryRenderedFeatures(e.point, { layers: [LAYER_CLUSTERS] });
if (!features.length) return;
const clusterId = features[0].properties?.cluster_id as number;
const clusterId = features[0]?.properties?.['cluster_id'] as number;
(map.getSource(SOURCE_ID) as mapboxgl.GeoJSONSource).getClusterExpansionZoom(
clusterId,
(err, expansionZoom) => {
if (err || expansionZoom == null) return;
const coords = (features[0].geometry as GeoJSON.Point).coordinates as [number, number];
const coords = (features[0]?.geometry as GeoJSON.Point).coordinates as [number, number];
map.easeTo({ center: coords, zoom: expansionZoom });
},
);
@@ -279,8 +279,8 @@ export function NeighborhoodPOIMap({
map.on('click', LAYER_UNCLUSTERED, (e) => {
const features = map.queryRenderedFeatures(e.point, { layers: [LAYER_UNCLUSTERED] });
if (!features.length) return;
const { name, categoryLabel, distance } = features[0].properties ?? {};
const coords = (features[0].geometry as GeoJSON.Point).coordinates.slice() as [
const { name, categoryLabel, distance } = features[0]?.properties ?? {};
const coords = (features[0]?.geometry as GeoJSON.Point).coordinates.slice() as [
number,
number,
];

View File

@@ -70,6 +70,20 @@ function makeListing(overrides: Partial<ListingDetail> = {}): ListingDetail {
{ id: 'media-1', type: 'image', url: 'https://example.com/img1.jpg', order: 0, caption: null },
{ id: 'media-2', type: 'image', url: 'https://example.com/img2.jpg', order: 1, caption: null },
],
usableAreaM2: null,
floor: null,
totalFloors: null,
nearbyPOIs: null,
metroDistanceM: null,
furnishing: null,
propertyCondition: null,
balconyDirection: null,
maintenanceFeeVND: null,
parkingSlots: null,
viewType: [],
petFriendly: null,
suitableFor: [],
whyThisLocation: null,
},
seller: {
id: 'seller-1',

View File

@@ -49,6 +49,20 @@ function makeListing(id: string): ListingDetail {
latitude: null,
longitude: null,
media: [],
usableAreaM2: null,
floor: null,
totalFloors: null,
nearbyPOIs: null,
metroDistanceM: null,
furnishing: null,
propertyCondition: null,
balconyDirection: null,
maintenanceFeeVND: null,
parkingSlots: null,
viewType: [],
petFriendly: null,
suitableFor: [],
whyThisLocation: null,
},
seller: { id: 's1', fullName: 'Seller', phone: '0901234567' },
agent: null,

View File

@@ -126,6 +126,20 @@ describe('generateListingJsonLd', () => {
latitude: 10.73,
longitude: 106.72,
media: [{ id: 'media-1', type: 'image', url: 'https://example.com/img1.jpg', order: 0, caption: null }],
usableAreaM2: null,
floor: null,
totalFloors: null,
nearbyPOIs: null,
metroDistanceM: null,
furnishing: null,
propertyCondition: null,
balconyDirection: null,
maintenanceFeeVND: null,
parkingSlots: null,
viewType: [],
petFriendly: null,
suitableFor: [],
whyThisLocation: null,
},
seller: { id: 'seller-1', fullName: 'Seller', phone: '0912345678' },
agent: null,