3
declare interface timezoneSyntax {
  region: string;
  en: {
    x: string;
    offset: {
      EST?: number;
      EDT?: number;
      [key: string]: number;
    };
  };
  it: {
   x: string;
  }
}

How to make the following object optional and also en generic?

en: {
    x: string;
    offset: {
      EST?: number;
      EDT?: number;
      [key: string]: number;
    };
  };

I have tried to convert en to [key: string]? But it is showing error. Please advice.

9
  • So en can be an object or a string? Commented Jul 22, 2019 at 11:36
  • Key for optional object. Commented Jul 22, 2019 at 11:37
  • I don't get you. Could you please give an example of the structure you want to describe? Commented Jul 22, 2019 at 11:39
  • @JonasWilms Done. Please check my edit. Commented Jul 22, 2019 at 11:42
  • 1
    You just copied the relevant part out of the interface, while that makes your question clearer (the whole interface was never relevant to the question though), you still haven't provided an example of the structure you want to describe. Commented Jul 22, 2019 at 11:45

3 Answers 3

9

Indexes of the form [key: string]: T can be considered as being always optional, so no need to specify it with the ? notation.

However, specifying an index signature like that forces all interface properties to have the same T type as the key. For example, region would result in

Property 'region' of type 'string' is not assignable to string index type '{ x: string; offset: { ... }; }'

This is because an index signature [key: string]: T simply dictates how all interface properties should be like. An alternative would be to use [key: string]: any but you would loosen up your type safety.

From my understanding, this is not a side effect that you want so you should reconsider the use of index keys in this interface and find a different approach.

Proposal

Instead of using a language-specific property name (en, it, es, etc), use the generic language as a name. If you also need to know what language you are dealing with, then that should be added to the language model as name.

You would end up with something like this:

declare interface timezoneSyntax {
  region: string;
  language: {
    name: string; // `en`, `it`, `es`, etc
    x: string;
    offset: {
      EST?: number;
      EDT?: number;
      [key: string]: number;
    };
  };
}

Further Reading

Indexable Types - Official TypeScript Documentation

Index Signatures - TypeScript Deep Dive

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

1 Comment

Offtopic Fun fact: [key: string]: ISomeInterface does not actually restrict the string on key.
9

Indexes of the form [key: string]: T can be optional. You can try to use Partial


   interface timezoneSyntax {
       page: Partial<{ [key: string]: number }>;
   }

Comments

0

BTW, It already becomes optional. But, if you still want to explicitly do that then you can do something like this.

declare interface timezoneSyntax {
  region: string;
  en: {
    x: string;
    offset:
      | {
          EST?: number;
          EDT?: number;
          [key: string]: number;
        }
      | {
          EST?: number;
          EDT?: number;
        };
  };
  it: {
    x: string;
  };
}

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.