0

I have a Dictionary interface where I want to have index type as string and values to be of string type.

interface One {
 [key: string]: string;
}

If I annotated this type to a constant variable that holds an object with no properties, then it doesn't give me an error.

const example: One = {}; // no error why?

Another question with the above approach is that const example = {} as One; this also works.

If I don't provide the index signature of the object then it gives me an error that you have missing properties.

interface Two {
 first: string;
 second: string;
}

const example2: Two: {}; // error missing properties
// to tackle this situation I used type assertion

const example3 = {} as Two; // no error

My question is why does the example variable accept an object with no properties?

You may have a question that why I want to have an object with no properties. The reason is I want to add some properties to that empty object later. In that case, should I do type assertion or type annotation?

Subrato Pattanaik
  • 5,331
  • 6
  • 21
  • 52
  • `{} as Two` is you saying "this is definitely a Two", overriding the compiler: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions. I don't know why you'd expect an error with `One`, the index type says any string-named property can be set, but doesn't _require_ any. – jonrsharpe Aug 12 '21 at 13:53
  • I am getting confused here does any string-named property includes empty object ? – Subrato Pattanaik Aug 12 '21 at 13:59
  • 1
    Clearly it does include the empty object, because the compiler isn't erroring. Look at it this way: `[key: string]: string` cannot require **every** possible value of `key` be present with a value, because there's an almost infinite range of strings that could be keys. Therefore they must all be optional, so an empty object is just as valid as one with one or many keys. – jonrsharpe Aug 12 '21 at 14:04
  • I understood your point. Last question if I use `[key: string]: string` should I use `const example: One = {}` or `const example = {} as One`? – Subrato Pattanaik Aug 12 '21 at 14:24
  • 1
    Put it this way: former allows the compiler to actually check if you're right; the latter insists that you are. – jonrsharpe Aug 12 '21 at 14:27
  • I am adding more properties to that object later so both are fine right? – Subrato Pattanaik Aug 12 '21 at 14:31
  • 1
    @jonrsharpe "an almost infinite range"... this got me wondering. I think since ES2016, strings can have a maximum of less than 2^53 UTF-16 characters, so that's at most (2^16)^(2^53-1) possible strings, which [WolframAlpha tells me](https://www.wolframalpha.com/input/?i=%28%282%5E16%29%5E%282%5E53-1%29%29) is less than 10^(10^17). So, much bigger than a googol, but significantly less than a googolplex. Not infinite of course, but you'd need a multiverse of computer memory to store a `{[key: string]: string}` if it required all keys to be actually present. Or use a `Proxy`. – jcalz Aug 12 '21 at 14:32
  • @jonrsharpe I think I understood the point about why index signature is optional. Would you want to write an answer? This might be helpful for people like me . – Subrato Pattanaik Aug 12 '21 at 15:10

1 Answers1

1

In the first example, you're just defining the type of indexes, you're not specify the indexes as you might by using in:

type Keys = 'first' | 'second'
type One = { [P in Keys]: string };

const one: One = {}; // Error: Type '{}' is missing the following properties from type 'One': first, second

In the second example you're asserting that the value is Two. You're telling typescript to trust you. If you want to use the Two type but make the fields optional, you can use the Partial utility type.

const example2: Partial<Two> = {}; // valid
const example3: Partial<Two> = { first: '1' }; // valid
const example3: Partial<Two> = { third: '3' }; // Error: Object literal may only specify known properties.
Daniel Gimenez
  • 18,530
  • 3
  • 50
  • 70