5

Is there a way to define a type that allows for a object with any properties, but enforces having at least 1 (unknown) property?

// this does not work

type Test = {
  [key: string]: any
}

const obj: Test = {} // this should give an error
const anotherObj: Test = { something: "thing" } // this should work
3
  • You can see typescriptlang.org/docs/handbook/… Commented Apr 28, 2022 at 9:17
  • @FahdLihidheb how is this useful? Do you have a solution? Commented Apr 28, 2022 at 9:42
  • @Tobias S. use a factory to create your Test objects and check in creation if there is at least one key. Commented Apr 28, 2022 at 9:47

2 Answers 2

4

This is the only solution I can think of (Thanks to the comment of @Fahd Lihidheb)

type NotEmpty<T> = keyof T extends never ? never : T

function createTest<T extends {[key: string]: any}>(test: NotEmpty<T>): T {
  return test
}

const obj = createTest({})                            // error
const anotherObj = createTest({ something: "thing" }) // works

I don't think it is possible with just a type definition. We have to use a factory method instead so we can infer the type of T and check if any keys exist.

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

Comments

1

I stumbled upon a possible answer when working on something else.

type NonEmptyObj<T extends Record<string, unknown>> = T extends Record<string, never> ? never : T;

This relies on Record<string, never> which defines an empty object. We check if T never extends an empty object.

Utilizing this test would look something like this:

function someFunction<T extends Record<string, unknown>>(foo: NonEmptyObject<T>) { ... }

TS playground link

Should you do this? Probably not. The error provided by this typing is quite unhelpful and the possible use-case very niche.

2 Comments

type IsNotEmptyObject<T extends Record<string, unknown>> = T extends EmptyObject ? false : true using type-fest's EmptyObject. github.com/sindresorhus/type-fest/issues/395 (see also: IfEmptyObject and IsEmptyObject)
Also: RequireAtLeastOne

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.