TypeError: Cannot read property 'defaultMeta' of undefined

Viewed 406

So I'm coding a search engine in TypeScript. I have this error, where like it tells me that index.domains[host] is undefined. But when I debug in vscode, it says everything is working fine and that defaultMeta does exist on every domain in the list. The error occurs in search.ts, line 27.

I am pretty new to TS, started in feburary this year.

Error that im getting:

TypeError: Cannot read property 'defaultMeta' of undefined
    at C:\none of ur business\search-engine\search\src\apis\search.js:21:49
    at Array.map (<anonymous>)
    at default_1 (C:\none of ur business\search-engine\search\src\apis\search.js:18:27)
    at Layer.handle [as handle_request] (C:\none of ur business\search-engine\search\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\none of ur business\search-engine\search\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\none of ur business\search-engine\search\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\none of ur business\search-engine\search\node_modules\express\lib\router\layer.js:95:5)
    at C:\none of ur business\search-engine\search\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\none of ur business\search-engine\search\node_modules\express\lib\router\index.js:335:12)
    at next (C:\none of ur business\search-engine\search\node_modules\express\lib\router\index.js:275:10)

search.ts:

import { readFileSync } from "fs";
import { filePaths } from "../../../config.json";

export default function(req, res) {
    res.setHeader("Access-Control-Allow-Origin", "*");

    if (req.query.q) {

        const timeStart = process.hrtime();

        const index = JSON.parse(readFileSync(filePaths.indexDb, "utf-8"));

        const query = req.query.q.toLowerCase()
        .replace(/[^\w\d ]/g, "");

        var results = index.crawled.filter(page => {
            return page.url.toLowerCase().includes(query) || page.meta.title?.toLowerCase()?.includes(query);
        });

        const resultsAmount = results.length;
        results = results.slice((req.query.pg || 0) * 20, (req.query.pg || 0) * 20 + 20);

        results = results.map(page => {
            const url = new URL(page.url);
            const host = /^(www\.)/.test(url.host) ? url.host.substr(4) : url.host;
            const defMeta = index.domains[host].defaultMeta; // here is the error

            return {
                url: page.url,
                title: page.meta.title === undefined ? defMeta.title : page.meta.title,
                desc: page.meta.desc === undefined ? defMeta.desc : page.meta.desc
            }
        });

        const timeEnd = process.hrtime(timeStart);
        const timeSecs = Math.round((timeEnd[0] * 1e9 + timeEnd[1]) / 1e9 * 100) / 100;

        return res.json({
            success: true,
            resultsAmount,
            timeTaken: timeSecs,
            results
        });
    } else {
        return res.status(400)
        .json({
            success: false,
            msg: "Invalid query"
        });
    }
}
1 Answers

Your errors points out that the field where defaultMeta should be called on does not exist. That is, domains[host] does not exist in line

const defMeta = index.domains[host].defaultMeta; // here is the error

This means that if domains[host] does not exist, you cannot continue to require field defaultMeta from it.

You can do this by surrounding your problematic line with an if condition which checks whether it's defined:

if (index.domains[host] !== undefined) {
  const defMeta = index.domains[host].defaultMeta; // here is the error

  return {
      url: page.url,
      title: page.meta.title === undefined ? defMeta.title : page.meta.title,
      desc: page.meta.desc === undefined ? defMeta.desc : page.meta.desc
  }
}

You see how I also included the following lines into the if statement. That's because you're using defMeta there which would not be defined if index.domains[host] is not defined.

Alternatively you could also use the optional chaining operator ?. to only access values in case they are defined. But here you would also have to then make sure future uses are checked (see all the places where I used ?.:

if (index.domains[host] !== undefined) {
  const defMeta = index.domains?.[host]?.defaultMeta; // here is the error

  return {
      url: page.url,
      title: page.meta.title === undefined ? defMeta?.title : page.meta.title,
      desc: page.meta.desc === undefined ? defMeta?.desc : page.meta.desc
  }
}

So perhaps you have to analyze why index.domains[host] is undefined in the first place. This could be because your const host = /^(www\.)/.test(url.host) ? url.host.substr(4) : url.host; line might have an error?!

Related