Home > Blockchain >  How can I get elements from a custom TypeScript type, while using variable key names?
How can I get elements from a custom TypeScript type, while using variable key names?

Time:08-25

I am using a custom type declared in TypeScript:

export type CustomType = {
  id: number;
  name: string;
  optionA: boolean;
  optionB: boolean;
  // dozens more boolean options...
};

I want to refer to this later with a variable rather than a known-at-compile-time fixed string, like this:

const customObject: CustomType = callApi();
for(keyName : possibleKeys) { // possibleKeys contains "optionA" and "optionB"
    if(customObject[keyName]) {
      // do stuff
    }
}

TypeScript says I can't do this, because

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'CustomType'.

The type itself is fine, as the following shows

console.log(customObject.optionA); // works
console.log(customObject["optionA"]); // works
const keyName = "optionA";
console.log(customObject[keyName]); // fails

I've found multiple resources for using variable keys to set data, but not much for getting data. I did try declaring an index signature but got numerous syntax errors (maybe because it's a type and not a plain old object?).

I made a fiddle demonstrating the above. Surprisingly, the log output shows that the code does work, even though it reports an error. My real build pipeline won't allow code with errors, though. How can I get around this?

CodePudding user response:

You can build your CustomType from arrays of property keys separated by data type, then use those arrays to later safely iterate the object. The arrays should be readonly arrays of string literals — I create them using const assertions below:

References:

TS Playground

const numberKeys = ['id'] as const;
const stringKeys = ['name'] as const;
const booleanKeys = [
  'optionA',
  'optionB',
  // dozens more boolean options...
] as const;

const allKeys = [...numberKeys, ...stringKeys, ...booleanKeys] as const;

type CustomType =
  & Record<typeof numberKeys[number], number>
  & Record<typeof stringKeys[number], string>
  & Record<typeof booleanKeys[number], boolean>;

declare function callApi (): CustomType;

const customObject = callApi();
    //^? const customObject: CustomType

// CustomType still looks like this:
customObject.id;
           //^? (property) id: number
customObject.name;
           //^? (property) name: string
customObject.optionA;
           //^? (property) optionA: boolean
customObject.optionB;
           //^? (property) optionB: boolean

for (const key of booleanKeys) {
    const value = customObject[key];
        //^? const value: boolean
}
  • Related