Home > front end >  Interface for object with multiple keys of same type with a unique key
Interface for object with multiple keys of same type with a unique key

Time:02-01

My question is somewhat similar to this: TypeScript: How to create an interface for an object with many keys of the same type and values of the same type?.

I'm trying to create an interface for an object which can have several keys, all optional, but with the same type. In this object, there's also 1 unique key with a boolean value.

At first, I was trying to use a mapped index signature like:

const foo : {
  [key in 'String 1' | 'String 2' | 'String 10']? : MyInterface
} = {}

However, with this approach, if I add another key like:

const foo : {
  valid : boolean
  [key in 'String 1' | 'String 2' | 'String 10']? : MyInterface
} = {}

TypeScript complains:

A mapped type may not declare properties or methods.

I can fix this by doing something like:

const foo : {
  [key in 'string_1' | 'string_2' | 'string_10' | 'valid']? : boolean | MyInterface
} = {}

which works, but as you can see, it would also mean that foo.string_10 could also be a boolean, which would be incorrect.

How can this be achieved?

CodePudding user response:

You're really close with your second code block, but you need to separate the valid: boolean object type from the indexed object type, and then use an intersection to join them. Since you're defining optional properties, I'm assuming you'll want a type alias for this to make it reusable, so:

type TheType = {
    [key in "String 1" | "String 2" | "String 10"]?: MyInterface;
} & {
    valid: boolean;
};

Alternatively, you can use Partial<Record<"String 1" | "String 2" | "String 3", MyInterface>> for the indexed object type; it does the same thing, it's just a style preference either way:

type TheType =
    Partial<Record<"String 1" | "String 2" | "String 3", MyInterface>>
    & {
        valid: boolean;
    };

Either way, here are some example uses:

// Valid, since all the string properties are optional
const foo1: TheType = {
    valid: true,
};

// Valid, has only allowed properties
const foo2: TheType = {
    valid: true,
    "String 1": { someProperty: "x"},
};

// Not valid as desired, has "excess" property
const badFoo: TheType = {
    valid: true,
    "Some Other String": { someProperty: "x"}, // Error here
};

Playground link - indexed type version
Playground link - Partial<Record<__>> version

CodePudding user response:

You can handle it in this way :

const foo : {
  [key in 'String 1' | 'String 2' | 'String 10']? : MyInterface
} | { valid : boolean} = {}

playground

  • Related