Home > Net >  Typing objects with unknown properties in TypeScript. How to do it properly?
Typing objects with unknown properties in TypeScript. How to do it properly?

Time:03-12

Let's say that there is a type:


interface ObjWithKnownKeys {
  prop: string;
}

And I need an object that contains objects of this type. I know that I can type it like this:

interface ObjWithUnknownKeysA {
  [key: string]: ObjWithKnownKeys;
}

const a: ObjWithUnknownKeysA = {};

// ❌ no error that 'someName' is possibly undefined
a.someName.prop;

for (const key in a) {
  const entry = a[key];
  // ✔️ no errors
  entry.prop;
}
for (const [key, entry] of Object.entries(a)) {
  // ✔️ no errors
  entry.prop;
}

Or like this:

interface ObjWithUnknownKeysB {
  [key: string]: ObjWithKnownKeys | undefined;
}

const b: ObjWithUnknownKeysB = {};

// ✔️ error that 'someName' is possibly undefined
b.someName.prop;

for (const key in b) {
  const entry = b[key];
  // ❌ error that entry is possibly undefined (but it's clear it's not for given key)
  entry.prop;
}
for (const [key, entry] of Object.entries(b)) {
  // ❌ error that entry is possibly undefined
  entry.prop;
}

But how should I type it to make sure that it will always work as expected?

EDIT AFTER AUTO CLOSE: There is no mention of --noUncheckedIndexedAccess flag in that thread that was marked as similar. I think this flag is a better answer.

CodePudding user response:

This is one of the pain points in TypeScript. By default, the compiler treats types with index signatures as if every possible property of the relevant key type is present and defined. This is convenient since you don't have to convince the compiler that a property is actually defined before using it:

interface StringIndex {
   [k: string]: string;
}
const str: StringIndex = { abc: "hello" };
str.abc.toUpperCase(); // okay

And you can easily iterate over keys/values:

for (const k in str) {
   str[k].toUpperCase(); // okay
}

for (const v of Object.values(str)) {
   v.toUpperCase(); // okay
}

// arrays have numeric index signatures
const arr: Array<string> = ["x", "y", "z"];
for (const s of arr) {
   s.toUpperCase(); // okay
}

Unfortunately, it's demonstrably unsafe:

str.boop.toUpperCase(); // no compiler error!            
  • Related