Conditioning types for uninitialized objects

Is there a way to create a conditional type that can determine if an object is empty?

For instance:

function test<T>(a: T): T extends {} ? string : never {
        return null
      }
   let o1: {}
   let o2: { fox? }
   let o3: { fox }
   test(o1)
   test(o2)
   test(o3) // this should be 'never'

Even though the conditional type also takes inheritance into account, in all 3 cases it returns 'string' but I actually want it to return 'never' if any property of the type is required (like o3)

UPDATE

When writing this question, my goal was to address a specific issue. I wanted to clarify my doubts rather than focus on the problem at hand and keep the question simple. Unfortunately, the answers I received did not quite hit the mark.

Essentially, I was attempting to create a function where the first argument is an object and the second one is optional only when the first argument can be completely partial (initialized with {}).

function test<T extends {}>(a: T, ...x: T extends {} ? [never?] : [any])
 function test(a, b) {
   return null
 }

let o1: {}
let o2: { fox? }
let o3: { fox }

test(o1) // should work
test(o2) // should work
test(o3) // should fail and require a second argument

Answer №1

Utilizing the keyof operator provides a simple solution for this task.

Keep in mind that never essentially represents an empty set.

type Foo = keyof {} // never
type Bar = keyof { a: 1, b: 2 } // "a" | "b"

In the context of your specific situation, it can be implemented as follows:

declare function f<T>(t: T): keyof T extends never ? string : never

const a = f({}) //string
const b = f({ a: 1 }) //never

edit

If you aim to treat an object with only optional properties as an empty object, additional type techniques can be utilized.

By borrowing the definition of OptionalPropertyOf from this question, we can define the following:

// Type Definitions
// Code goes here...

Adjusting the definition of f slightly leads to the desired outcome:

// Code goes here...

With these adjustments, you can achieve the expected results when implementing f:

// Code goes here...

Playground link

Answer №2

This code snippet does not utilize a conditional type and features different coding compared to your original question. It may seem irrelevant, but I included it as a reference point towards finding a potentially helpful answer.

The same result can be achieved using overloads:

function test(a: {}): string;
function test(a: Record<string | number | symbol, any>): never;
function test(a: {} | Record<string | number | symbol, any>): string | never {
    if (Object.keys(a).length === 0) {
        return 'test';
    } else {
        throw new Error();
    }
}

const a = test({});       // type string
const b = test({ a: 1 }); // type never

Playground link

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

How to Retrieve a Global Variable in an Angular Template

Is there a way to access a global variable from an Angular template? let unableToAccess = false; @Component({ selector: 'app-payment', templateUrl: './buy.component.html', styleUrls: ['./buy.component.scss'] }) export ...

It seems that Ionic 2 does not support the registration of custom HTML tags

Encountering a problem with Ionic 2 and custom components. Developed a component to show in a list, serving as the list item. However, my app crashes when attempting to use the custom HTML tag. The stack trace is provided below. Uncertain about the issue. ...

Can TypeScript be implemented within nuxt serverMiddleware?

I recently began diving into the world of nuxtjs. When setting up, I opted to use typescript. Initially, everything was running smoothly until I decided to incorporate express in the serverMiddleware. Utilizing the require statement to import express funct ...

Executing ts-node scripts that leverage imported CSS modules

Is there a way to execute scripts that utilize css modules? I am currently working on a typescript migration script that I would like to execute using ts-node. The ideal scenario would be to keep the script's dependencies separate from the React comp ...

Tips for creating unit tests for my Angular service that utilizes the mergeMap() function?

As a beginner with the karma/jasmine framework, I am currently exploring how to add a test case for my service method shown below: public getAllChassis(): Observable<Chassis[]> { return this.http.get('chassis').pipe( merge ...

Generate a new data type based on the value of a single attribute within a collection of objects

Is there a way to extract a specific property of a combined type and generate a new type from it? Consider the following example: type Actions = | { type: "ADD_COLUMN"; newColumnIndex: number; column: SelectorColumnData; } | { type: ...

Enforce numerical input in input field by implementing a custom validator in Angular 2

After extensive research, I was unable to find a satisfactory solution to my query. Despite browsing through various Stack Overflow questions, none of them had an accepted answer. The desired functionality for the custom validator is to restrict input to ...

Guide on assigning JSON response values to TypeScript variables in Angular 4

I'm just starting with Angular 4 and I'm attempting to retrieve a JSON value using http.post. The response I'm receiving is: {"status":"SUCCESS"} component onSubmit(value: any) { console.log("POST"); let url = `${this.posts_Url}`; t ...

The function signature '(event: ChangeEvent<HTMLInputElement>) => void' does not match the expected type 'ChangeEvent<HTMLInputElement>'

This is my first time using TypeScript to work on a project from the ZTM course, which was initially written in JavaScript. I am facing an issue where I am unable to set a type for the event parameter. The error message I receive states: Type '(event: ...

The header component does not update properly post-login

I am currently developing a web-app using Angular 8. Within my app, I have a header and login page. My goal is to update the header after a user logs in to display information about the current logged-in user. I attempted to achieve this using a BehaviorS ...

Utilize localStorage.getItem() in conjunction with TypeScript to retrieve stored data

Within my codebase, I have the following line: const allGarments = teeMeasuresAverages || JSON.parse(localStorage.getItem("teeMeasuresAverages")) || teeMeasuresAveragesLocal; Unexpectedly, Typescript triggers an alert with this message: Argument ...

Deduce the generic types of conditional return based on object property

My goal is to determine the generic type of Model for each property. Currently, everything is displaying as unknown[] instead of the desired types outlined in the comments below. playground class Model<T> { x?: T } type ArgumentType<T> = T ...

Ensure the proper sequence of field initialization within a TypeScript class constructor

Is there a way to ensure the proper initialization order of class fields in TypeScript (4.0) constructors? In this example (run), this.x is accessed in the method initY before it's initialized in the constructor: class A { readonly x: number rea ...

Creating an array of objects in Angular 2

I'm facing an issue with the following expression: public mySentences:Array<string> = [ {id: 1, text: 'Sentence 1'}, {id: 2, text: 'Sentence 2'}, {id: 3, text: 'Sentence 3'}, {id: 4, text: 'Sen ...

Google Maps on Angular fails to load

I'm currently working on integrating AGM into my Ionic 2 project. app.module.ts ... import { AgmCoreModule } from '@agm/core'; import { DirectionsMapDirective } from '../components/directions-map'; @NgModule({ declarations: [ ...

What is the process for dynamically loading a concrete implementation and customizing object creation through parameterization?

Concern I am currently developing a Chrome Extension that is capable of receiving commands and is built using TypeScript. My objective is to separate out concrete implementations of a class into individual files that can be loaded dynamically. Illustrat ...

Tips for executing numerous asynchronous tasks in Ionic 3 and closing a loader once all tasks are completed

Currently, I am in the process of developing an Ionic 3 application that offers the feature to cache a list of articles content on demand. The implementation involves utilizing Storage which employs promises for its operations. The code snippet I have wri ...

The interaction between Nextjs router and useEffect resulting in unintended re-rendering

I'm currently facing a challenge with Next.js's next/navigation router. In my component, I have a series of useEffects implemented. Strangely, when I call router.replace, one of the effects runs twice or even infinitely in some cases. As a result ...

The most suitable TypeScript type for a screen being utilized again in react-navigation v5

When it comes to typing screens under react-navigation v5, I usually follow a simple pattern: // Params definition type RouteParamsList = { Screen1: { paramA: number } Screen2: undefined } // Screen1 type Props = StackScreenProps<R ...

Creating a structure within a stencil web component

In my current project, I am utilizing Stencil.js (typescript) and need to integrate this selectbox. Below is the code snippet: import { Component, h, JSX, Prop, Element } from '@stencil/core'; import Selectr from 'mobius1-selectr'; @ ...