2

I need to access an object property in Typescript for which two levels are dynamic, e.g. object[key1][key2].
Even though I believe I do the appropriate checks, I still get a type error.
(object[key1] as any)[key2] works but doesn't seem very elegant.

Is there a better way? Would really appreciate an idea.

Below the code + playground.

const POIs = {
  amenity: {
    bar: {
      activity: "night",
      icon: "glass"
    }
  },
  building: {
    supermarket: {
      activiy: "day",
      icon: "warehouse"
    }
  }
}

interface noiseData {
  tags: {
    [T in keyof typeof POIs]: keyof typeof POIs[T]
  }
}


function parseNoiseSources(nss: noiseData[]): void {
  for (const ns of nss) {
    for (const category in POIs) {
      const cat = category as keyof typeof POIs
      const key = ns.tags[cat]
      if (cat in ns) {
        const obj = POIs[cat]
        if (key in obj) {
          const act = POIs[cat][key].activity
          // Below satisfies the compiler but seems redundant
          // const bct = (POIs[cat] as any)[key].activity
        }
      }
    }
  }  
}

The exact error message is this: Element implicitly has an 'any' type because expression of type '"bar" | "supermarket"' can't be used to index type '{ bar: { activity: string; icon: string; }; } | { supermarket: { activiy: string; icon: string; }; }'. Property 'bar' does not exist on type '{ bar: { activity: string; icon: string; }; } | { supermarket: { activiy: string; icon: string; }; }'.

Playground: https://www.typescriptlang.org/play?#code/MYewdgzgLgBACgeQJIRgXhgbwFAxgQwFsBTMASygE8AuLXPGAI3wCdacGH9goyA3CjRgAicgHMAFlGEAaepzKgwtYWIA2+CBGHyYAX3p65eRgFcyagCZkwY9roimADsRaFWAa2JR7nPN14BIWFLfEpZXTxFcBUAd1ZiCRBTCGIdTgM8AwNsGyhXADNuYhgwEDJUgBF8KHw6PFqxCF8GAG0AFRgbGC9KEAKYKhd++GQIAF1aXpGh4hHEFA7xw2wc7ALTMB4ycBgnVlSAOXLUgGVklmBiCAAKSGbSk+Jq2tbxgEpaPnLLepgCkAsGA3JTQUqoEb3d5-PAAoEg8Bg4A1YhiQGULpgUYoaEcPyg2DI2AYImo9EEVDTAazeZjSIwAk9YgYjCQAB0jQgrSJyz8XQGIJqmPBuPpeEZIEYACt0NiuTyxfzgb1hZKpaK+ZxGQFZQt5TVxq1euM2QF+IJFXgAPRWmAAIWIahAsRgEBqFQKZGugwkJVAhCcFlcTFMsFSxEIqBYxEsm1CYCglpgNoZiNgjB4spueu5BopBDAlHeRuZJrNAioisyfmrWUMeFWQA

Thanks a lot for any help!

1 Answer 1

1

you should add type for your POIs object:

interface DataFrame {
  activity: string;
  icon: string;
}
type Keys = 'amenity' | 'building'
type Data = Record<Keys, Record<string, DataFrame>>


const POIs: Data = {
  amenity: {
    bar: {
      activity: "night",
      icon: "glass"
    }
  },
  building: {
    supermarket: {
      activity: "day",
      icon: "warehouse"
    }
  }
}

interface noiseData {
  tags: {
    [T in keyof typeof POIs]: keyof typeof POIs[T]
  }
}


function parseNoiseSources(nss: noiseData[]): void {
  for (const ns of nss) {
    for (const category in POIs) {
      const cat = category as keyof typeof POIs
      const key = ns.tags[cat]
      if (cat in ns) {
        const obj = POIs[cat]
        if (key in obj) {
          const act = POIs[cat][key].activity // no error
          // Below satisfies the compiler but seems redundant
          // const bct = (POIs[cat] as any)[key].activity
        }
      }
    }
  }
}

bar and supermarket objects should have same types

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.