Is there a way to ensure that the object in TypeScript contains a specific property?

type Information = Record<string, string | number | boolean | null>;

Presenting my data structure, however, I am unable to implement it correctly.

I aim to generate an error if no properties are added to an object.

const newObj: Information = {} // should trigger a type error

I experimented with various TypeScript utility types but could not achieve the desired outcome.

Answer №1

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Determining the return type of a function by analyzing its argument(s)

I'm interested in defining a method within a class that will have its type based on the argument provided in the constructor. For example: class A { private model: any; constructor(model: any) { this.model = model; } getModel( ...

JavaScript - Modifying several object properties within an array of objects

I am attempting to update the values of multiple objects within an array of objects. // Using a for..of loop with variable i to access the second array and retrieve values const AntraegeListe = new Array(); for (let i = 0; i < MESRForm.MitarbeiterL ...

Assign a class to a button created dynamically using Angular

While working on my project, I encountered an issue where the CSS style was not being applied to a button that I created and assigned a class to in the component.ts file. Specifically, the font color of the button was not changing as expected. Here is the ...

Ways to obtain a tab and designate it as the default in angular when using angular material Tabs

I am facing an issue with accessing tabs within a nested component. The parent component contains the tab feature and to reach the tabs inside the child component, I am using the following code: document.querySelectorAll('.mat-tab-group'); The a ...

Encountering NgRx Select Issues While Trying to Access Nested Properties

I've encountered TypeErrors while using NgRx select functions to access nested properties. In my app.module.ts, I have configured the root store as follows: StoreModule.forRoot({ app: appReducer }), The selectors causing errors are related to some ...

In TypeScript, the 'fs' module can be imported using the syntax `import * as fs from "

import * as fs from "fs"; const image1 = Media.addImage(document, fs.readFileSync("new.png")); Here is the configuration from my tsconfig.json: "compileOnSave": false, "compilerOptions": { "importHelpers": true, "outDir": "./dist/out-tsc", ...

Refine current attributes of an object in Typescript

In typescript, I have an object of type any that needs to be reshaped to align with a specific interface. I am looking for a solution to create a new object that removes any properties not defined in the interface and adds any missing properties. An exam ...

What is preventing TypeScript from resolving assignment in object destructuring?

Consider the code snippet below: interface Foo { a?: number b?: number } function foo(options?: Foo) { const { a, // <-- error here b = a } = (options ?? {}) return [a, b] } Why does this code result in the followi ...

How to format a date in ngModel using Angular 9 and above

Is there a way to format the date displayed in my input using ngModel to follow a specific format like 'MM/dd/YYYY'? Can this be achieved by using ngModel? For example, could we do something like model[(ngModel)]="data.targetDate | date:'MM ...

What is the process for creating a PickByValue data type?

The TypeScript language comes with a built-in Pick type, which is defined as follows: type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; If you were to create a custom PickByValue type, how would you implement it to achieve the following func ...

The array containing numbers or undefined values cannot be assigned to an array containing only numbers

Currently facing an issue with TypeScript and types. I have an array of IDs obtained from checkboxes, which may also be empty. An example of values returned from the submit() function: const responseFromSubmit = { 1: { id: "1", value: "true" }, 2: ...

Issue Encountered in Cloud Function with Nanoid Typescript: Error stating that typeof import does not have any call signatures

Importing import * as customID from "nanoid"; var newID: string = "" const alphaNums: string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; function createNewID() { newID = customID(alphaNums, 10) ...

Is it feasible to determine the precise class of an object while utilizing a variable that possesses a union type in Typescript?

Currently delving into Typescript and running tests. Upon using console.log, I received an object. Given its typed nature, I anticipated it to accurately determine the type of variable c. interface Car { gears: number } interface Bike{ gears: number ...

Tips for accessing and modifying local files in Angular 2

Is there a method in Angular 2 to access files from an absolute path? I have utilized the 'filesaver' library for file saving, storing the files locally in txt/json formats. For instance: let blob = new Blob([document.getElementById(&apos ...

The 'then' property is not found on the type 'CloudFunction<Change<DocumentSnapshot>>'

Encountered an error: The property 'then' does not exist on type 'CloudFunction>' in my Firebase cloud function. Does anyone have a solution? exports.rebuildFormTriggerClientDetails = functions.firestore. document('clientDeta ...

Get the file without specifying type in request - Angular

Is it possible to download a file solely through the response without specifying a responsetype in the header? I am looking for a way to download the file without including any additional parameters in the header. ...

Tsc encounters issues when interacting with AWS services

When attempting to compile TypeScript code into JavaScript using tsc, I encountered constant crashes specifically related to AWS code within the node_modules directory. Despite my efforts to resolve the issue by adding skipLibCheck to my tsconfig file, inc ...

How can we avoid a runtime error when attempting to filter an array that may not be present at a certain point in

Encountering a runtime error with my reducer state chunk - specifically a TypeError stating that an intermediate value is not iterable. This occurs when the object, childGroup, may not be present in the state at a given moment. Any solutions on how to avoi ...

Building a multi-platform desktop application using Angular and Electron integrated with ngx

Having developed an Angular application, there is now a need for a desktop version as well. Electron was used to run the application, and everything is functioning as intended. However, an issue arises with localization. In the electron application, only ...

Is it possible to alter the background color once the content of an input field has been modified?

I am working with an angular reactive form and I want to dynamically change the background color of all input fields when their value is changed. Some of these input fields are pre-populated and not required. I came across a potential solution on Stack Ove ...