You have a few options:

  1. You can use an index signature type that allows any string or any number, for instance:

    let myObj: {[key: string]: number} = {};
    myObj[prop] = value;
    

    ...allows any string property name, with the values expected to be numbers. (Or you can use {[key: number]: number} to make the keys numbers. string and number are your only two index signature options.)

  2. You can use the Record utility type, for example Record<string, number> which does much the same thing as the above:

    let myObj: Record<string, number> = {};
    myObj[prop] = value;
    
  3. You can use a Map instead of an object:

    let myObj: Map<string, number> = new Map();
    myObj.set(prop, value);
    

In all three of those, number as the value type is just an example, it can be any type you want (including a union type), or unknown if you won't know the type, or any if you want to allow any type.

It may be obvious, but I'll say it anyway: This does mean TypeScript can't help you with using the wrong property name on the object. :-) But that's inevitable if the property name is a runtime thing.

🌐
Total TypeScript
totaltypescript.com › the-empty-object-type-in-typescript
The Empty Object Type in TypeScript | Total TypeScript
April 2, 2024 - Instead of representing an empty object, it represents any value except null and undefined. This is because TypeScript's type system is structural, not nominal.
🌐
Bobby Hadz
bobbyhadz.com › blog › typescript-interface-empty-object
How to initialize a typed Empty Object in TypeScript | bobbyhadz
The index signature in the examples means that when an object is indexed with a string, it will return a value of any type. You can also use the Record utility type to initialize a typed empty object.
Discussions

How to access a possibly empty array by index?
if (matches == null). This will check for both null and undefined. Doing typeof matches === undefined doesn't really make sense. typeof returns a string, so you'd have to do typeof matches === 'undefined' if you wanted to use typeof. Nowadays it's possible to just test it against null or undefined directly, so there is no need to use typeof More on reddit.com
🌐 r/typescript
24
3
March 19, 2024
TypeScript empty object for a typed variable - Stack Overflow
Either you want user to be of type ... allow an empty object. Right now, the compiler is correctly telling you that user is not a User. – jcalz · I don't think this should be considered a proper answer because it creates an inconsistent instance of the type, undermining the whole purpose of TypeScript... More on stackoverflow.com
🌐 stackoverflow.com
Intersection of empty object type with empty object type is missing index signature
There was an error while loading. Please reload this page · TypeScript Version: 2.7.0-dev.20171122 More on github.com
🌐 github.com
0
November 22, 2017
How to assign the appropriate types to this empty object?
Use either ‘Map’ or ‘Record’ as the type for ‘lookup’. In this case (and many) Record is more appropriate but both are absolutely fine. So try ‘const lookup: Record = {}’ More on reddit.com
🌐 r/typescript
8
2
September 12, 2022
🌐
Reddit
reddit.com › r/typescript › how to access a possibly empty array by index?
r/typescript on Reddit: How to access a possibly empty array by index?
March 19, 2024 -

this is my situation

let matches : string[] | null = topic.match(this._DEVICE_TOPIC_REGEXP);
console.log("handleNewMeasure, topic", topic, "matches", matches);
if (typeof matches === undefined ) {
return;
}
let device_id = matches[1];

I cannot go on because last line warns me that it could be empty

🌐
Wanago
wanago.io › home › managing objects with unknown structures in typescript using index signatures
Managing objects with unknown structures in TypeScript using index signatures
January 24, 2022 - We can deal with the above issue by creating multiple index signatures or using the in keyword. It is also worth mentioning the {} type. Unfortunately, it does not mean “any empty object” and accepts any non-null value as well. The @typescript-eslint/eslint-plugin package throws an error when we use it.
🌐
GitHub
github.com › Microsoft › TypeScript › issues › 20225
Intersection of empty object type with empty object type is missing index signature · Issue #20225 · microsoft/TypeScript
November 22, 2017 - type Dictionary = { [name: string]: string }; const intersectDictionaries = <F1 extends Dictionary, F2 extends Dictionary>( d1: F1, d2: F2, ): F1 & F2 => Object.assign({}, d1, d2); const testDictionary = <T extends Dictionary>(_value: T) => { }; const d1 = {}; testDictionary(d1); // OK, d1 is inferred to be {} const d2 = intersectDictionaries(d1, d1); testDictionary(d2); // error, d2 is inferred to be {} // compile error on the above line: // ts-braces-not-assignable.ts(13,16): error TS2345: Argument of type '{}' // is not assignable to parameter of type 'Dictionary'. // Index signature is missing in type '{}'. const d3 = { s: '', }; testDictionary(d3); // OK const d4 = intersectDictionaries(d1, d3); testDictionary(d4); // OK const d5 = intersectDictionaries(d3, d1); testDictionary(d5); // OK const d6 = intersectDictionaries(d3, d3); testDictionary(d6); // OK
Published   Nov 22, 2017
Find elsewhere
🌐
Reddit
reddit.com › r/typescript › how to assign the appropriate types to this empty object?
r/typescript on Reddit: How to assign the appropriate types to this empty object?
September 12, 2022 -

This is what I have so far

interface Book {
  "book-title": string;
  "id": string;
  "description": string;
  "tagId": string;
  "tagName": string;
}
const hydrateNotes = (input: Book[]) => {
  const lookup = {};
  for (let note of input) { 
    if (!lookup[note.id]) { 
      lookup[note.id] = note;
      lookup[note.id].tags = [];
    }
    if (note.tagId && note.tagName) { 
      lookup[note.id].tags.push({ 
        id: note.tagId,
        name: note.tagName,
      });
    }
  }
  return lookup;
};

I'm getting errors on lookup[note.id] saying No index signature with a parameter of type 'string' was found on type '{}

The input is an array of Book interface, and the end result for lookup would be like this jsbin

🌐
GitHub
github.com › Microsoft › TypeScript › issues › 23023
Empty object type assignable to type with index signature · Issue #23023 · microsoft/TypeScript
March 30, 2018 - TypeScript Version: 2.9.0-dev.20180330 · Search Terms: Empty object type, index signature · Code · let a: {} = '123'; let b: { [key: string]: number } = { value: 1 }; b = a; Expected behavior: Type Error on 'b = a'. It is possible to assign almost anything to value of Empty object type.
🌐
Bobby Hadz
bobbyhadz.com › blog › typescript-check-if-object-is-empty
Check if an Object is Empty in TypeScript | bobbyhadz
index.ts · Copied!import isEmpty ... this article is available on GitHub · The lodash.isempty method checks if the supplied value is an empty object, collection, Map or Set....
🌐
GitHub
github.com › microsoft › TypeScript › issues › 6274
Empty object is not assignable to type argument with constrained index signature · Issue #6274 · microsoft/TypeScript
December 28, 2015 - microsoft / TypeScript Public · Notifications · Fork 12.3k · Star 95.2k · New issue · Jump to bottom · Closed · tinganho opened this issue · Dec 28, 2015 · 2 comments · Closed · tinganho opened this issue · Dec 28, 2015 · 2 comments · Labels · By Design · Deprecated - use "Working as Intended" or "Design Limitation" instead · Copy link · Contributor · interface B { [index: string]: string; } class A<T extends B> { a: T = {}; // Error b = {} as T; // No error } let b: B = {}; // No error ·
Top answer
1 of 2
64

The definition for Record is:

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

When creating a type like type MyType = Record<string, string>;, inlining Record leads to the following type:

type MyType = {
    [P in string]: string;
};

This is saying to create an object type with string property names within the set string. Since string is unbounded there's unlimited possibilities of strings (unlike a union of string literal types like "prop1" | "prop2")... so it's describing an object that can have any number of properties with any name, with the only restriction being that the properties must have a type of string.

So yes, from a type checking perspective it's basically equivalent to the example with the index signature without a mapped type ({ [index: string]: string; }.

Use a plain index signature

Using Record in this fashion is a little strange though and many people might not understand what's going on. A more common way to express intent when there can be any number of properties, is to not use a mapped type:

type ObjectWithStringProperties = {
    [index: string]: string;
};

This has the added benefit of helping explain what the key is supposed to be. For example:

type PersonsByName = {
    [name: string]: Person;
};
const collection: PersonsByName = {};

Note that in this way the types are different because a developer using an object with this type will have this extra described key name information to look at in their editor.

Using Record

Note that Record is usually used like the following:

type ThreeStringProps = Record<"prop1" | "prop2" | "prop3", string>;
// goes to...
type ThreeStringProps = { [P in "prop1" | "prop2" | "prop3"]: string; };
// goes to...
type ThreeStringProps = {
    prop1: string;
    prop2: string;
    prop3: string;
};
2 of 2
13

Whether it is a good idea to use Record instead of a plain index signature may be a matter of debate (as David Shereet points out in his answer). Also the fact that you can do a lot more thing with Record then you can with a simple index signature is also something that should be mentioned.

The main part of this question (in my reading) is whether the two types are the same. They are obviously declared in different ways but are they the same type. While they are obviously compatible (that is you can assign one to the other and vice-versa) the question is are there corner cases where this is not possible.

While it's hard to find an exhaustive list of what you can do with a type, Matt McCutchen in this answer provides an interesting type that detects weather the readonly modifier is present (something that simple compatibility does not detect the difference between). I would surmise that if Record and an index signature are the considered the same in the way Matt uses them there (as part of the signature of a generic function) they are pretty much the same type declared in a different way:

type IfEquals<X, Y> =
    (<T>() => T extends X ? 1 : 2) extends
    (<T>() => T extends Y ? 1 : 2) ? "Y" : "N";

let same : IfEquals<{x: string}, {x: string}>= "Y"
let notsame : IfEquals<{ y: string }, { x: string }>= "N"
let notsamero: IfEquals<{ readonly x: string }, { x: string }> = "N"
let samerecord: IfEquals<{ [x: string]:string }, Record<string, string>> = "Y"

As we can see in the last example the type of samerecord is Y meaning that the compiler treated the two types as being the same thing. Thus I would surmise { [x: string]:string } and Record<string, string> are exactly the same thing.

🌐
Medium
raihankabir862.medium.com › how-to-define-a-proper-type-for-an-empty-object-in-typescript-with-the-help-of-generic-a936a69859af
How to define a proper type for an empty object in Typescript with the help of Generics | by Raihan kabir | Medium
January 6, 2024 - In our daily work with TypeScript, we often find the need to define empty objects. However, there are numerous bad practices when it comes to creating proper type definitions. I have observed many developers creating type with the help of index signatures like this:
🌐
DhiWise
dhiwise.com › blog › design-converter › typescript-empty-object-guide-best-practices
Understanding the TypeScript Empty Object
March 3, 2025 - The way TypeScript handles empty objects depends on type rules, object literals, and assignable values.
🌐
Reddit
reddit.com › r/typescript › how to declare empty object in typescript?
r/typescript on Reddit: How to declare empty object in TypeScript?
September 12, 2021 -

I know this is a really basic question, and I've tried to look at similar questions and didn't understand it so I apologize.

I'm translating my JavaScript code to TypeScript, and have a lot of code that looks similar to this:

	if (!user_dict.options) {
		user_dict.options = {}
	}

This produces the error "property options does not exist on type {}" for both lines. How can I establish an empty object like this, if I don't know what type of variables will later be stored? I have hundreds of empty variable declarations like this, and I can't know at this point in the code the "type" of variable being stored later, so I don't understand how I'm supposed to handle this using TypeScript?

🌐
Tim Mousk
timmousk.com › blog › typescript-empty-object
How To Initialize An Empty Typed Object In TypeScript? – Tim Mouskhelichvili
March 2, 2023 - This article explains different methods to initialize an empty typed object in TypeScript with code examples.
🌐
Lightrun
lightrun.com › answers › microsoft-typescript-empty-type-inferred-by-objectentries
Empty type inferred by Object.entries
TypeScript Version: 2.7.1 · Search Terms: Object entries empty TS2365 · Code · let o: any = {x: 5}; let p = Object.entries(o).map(([k, v]) => v + 1); Compile command: tsc --lib es2017,es2017.object a.ts · Expected behavior: This should compile without any error, assuming v: any.
🌐
codestudy
codestudy.net › blog › define-an-empty-object-type-in-typescript
TypeScript: How to Define an Empty Object Type That Can't Hold Any Values — codestudy.net
To define a strict empty object type in TypeScript that cannot hold any values: Avoid {}, object, null, or undefined—they do not enforce emptiness. Use index signatures with never for string, number, and symbol keys to block all properties.