4

I want to declare a simple type to replace any in a piece of code. I know it will be some object-ish argument, so I could use Record<string, unknown>, but I'd rather be a little more specific.

This would be ideal:

type MyObject = Record<string, string | string[] | number | boolean | MyObject>

but it gives the error

Type alias 'MyObject' circularly references itself.ts(2456)

I can get around this by cheating with interfaces:

type MyObject<T> = Record<string, string | string[] | number | boolean | T>

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IMyObject extends MyObject<IMyObject>{}

Is there a way to do what I want, or should I just stick to Record<string, unknown>?

2 Answers 2

9

The compiler gives up before it can realize that the type you are specifying is recursive in a supported way, because it does not probe the definition of the Record utility type before checking for circularity. This is a design limitation of TypeScript. See microsoft/TypeScript#41164 for an explanation.

The fix here is to replace Record<string, XYZ> with what it eventually becomes, a type with a string index signature like { [k: string]: XYZ }:

type MyObject = 
  { [k: string]: string | string[] | number | boolean | MyObject } // okay

which works without error.

Playground link to code

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

Comments

1

You don't need to make it a generic

type MyObject = Record<string, string | string[] | number | boolean | IMyObject>
interface IMyObject extends MyObject {}

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.