In TypeScript, there isn't a specific data type called ValidData
that represents "an object of type Data
with at least one property". Therefore, you cannot define variables like const obj1: ValidData = {⋯}
. Even though you would want to write:
const obj1: ValidData = { okay: 123 }; // okay
const obj2: ValidData = { okay: 456, ok: 789 }; // okay
const obj3: ValidData = {}; // error!
Unfortunately, there is no built-in ValidData
type in TypeScript that fits your requirements.
However, you can create a generic type called ValidData<T>
that acts as a constraint on a type T
, ensuring that T extends ValidData<T>
if and only if T
has at least one property and is of type Data
. Here's an example:
type ValidData<T extends Data> =
T & (keyof T extends never ? { needAtLeastOneProperty: "oops" } : unknown);
This conditional type checks if the type T
has any known keys by comparing it to the impossible never
type. Depending on whether T
has keys or not, it creates the appropriate ValidData<T>
.
type Okay = ValidData<{ okay: number }>;
// type Okay = { okay: number; }
type AlsoOkay = ValidData<{ okay: number, ok: number }>;
// type AlsoOkay = { okay: number, ok: number };
type NotOkay = ValidData<{}>;
// type NotOkay = { needAtLeastOneProperty: "oops"; }
To avoid redundancy, you can use a generic helper function that infers the type T
for you:
const asValidData = <T extends Data>(t: ValidData<T>) => t;
Then, you can utilize this function to validate objects as follows:
const obj1 = asValidData({ okay: 123 }); // okay
const obj2 = asValidData({ okay: 456, ok: 789 }); // okay
const obj3 = asValidData({}); // error!
// ----------------------------------> ~~
// Argument of type '{}' is not assignable to
// parameter of type '{ needAtLeastOneProperty: "oops"; }'.
This approach ensures that invalid empty objects are rejected with clear error messages for developers to understand.
While we're using const obj1 = asValidData({⋯})
instead of the desired const obj1: ValidData = {⋯}
, the difference is minimal when considering functionality.
Playground link to code