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

Sort your list efficiently with a custom hook in React using Typescript

I've been working on developing a custom hook in React that sorts an array based on two arguments: the list itself and a string representing the key to sort by. Despite trying various approaches, I haven't been able to find a solution yet. I&apos ...

The element 'mat-toolbar' is unrecognized and not known:

Encountering an issue while executing karma tests - the error message indicates that 'mat-toolbar' is not a recognized element within the application. Here are some steps to troubleshoot this problem: 1. Confirm whether 'mat-toolbar' is ...

An issue has occurred: Failure to execute spawnSync PATH/target/node/node ENOENTNGCC. Please refer to the

Attempting to initiate my angular project using ./mvnw is resulting in an error when the build runs ng build --configuration development. The error message thrown reads as follows: Generating browser application bundles (phase: setup)... [INFO] /home/use ...

Having trouble typing computed values in Vue Composition API with TypeScript?

I'm attempting to obtain a computed value using the composition API in vue, and here is the code I am working with: setup() { const store = useStore(); const spaUrls = inject<SpaUrls>('spaUrls'); const azureAd = inject<AzureAd ...

the behavior subject remains static and does not update

Working on setting my language in the BehaviorSubject with a default value using a LanguageService. The service structure is as follows import {Injectable} from '@angular/core'; import * as globals from '../../../environments/globals'; ...

I have a question about TypeScript mapped types. Why is it not possible to retrieve the keys of a union of interfaces?

Below is the code snippet that I am working with: interface Data { A: { a1: string; a2: string; }; B: { b1: number; b2: string; }; } type TransformDataKey<V extends string, T extends string> = `--${V}-${T}`; type TransformDa ...

Displaying FontIcon in a NativeScript alert box

Would it be possible to display a fonticon on a Nativescript dialog? Similar to this example? dialogs.alert({ title: // set icon as text message: "Check-in Successful" }).then(()=> { console.log("Dialog closed!"); }); Is it feasible to ...

Unable to detect tsc after installing globally within Windows Sandbox

I followed the instructions provided here to install TypeScript globally. npm install -g typescript After installing both inside vscode and outside, I encountered an issue where tsc --version does not work and shows 'tsc is not recognized'. Int ...

The Express request parameter ID throws an error due to the index expression not being of type 'number', causing the element to implicitly have an 'any' type

Is there a way to assign a type to an ID request parameter? It appears that the types of Express treat request params as any. This is the code snippet where I am trying to access the ID from the request: const repository: Repository = { ...reposit ...

Angular 6: A guide to dynamically highlighting navbar elements based on scroll position

I am currently building a single page using Angular 6. The page is quite basic, and my goal is to emphasize the navbar based on scrolling. Below is the code snippet I am working with: .sticky { position: sticky; top: 0; } #i ul { list-style-type: ...

When inserting a child element before the myArray.map(x => ) function, it results in rendering only a single child element from the array

Sorry for the confusion in my explanation, but I'm encountering an issue with displaying elements from an array. Here is the code snippet I am working on. Currently, the myArray contains 10 elements. When I place the <LeadingChild/> component ...

Errors related to Typescript are causing issues with the stock installation of Next.js

Whenever I use typescript with create-next-app, my tsx files are filled with numerous "Problems" messages. These errors only appear in Visual Studio Code and do not affect the build process. I have tried uninstalling vscode, removing all extensions, and ...

Is there a universal method to transform the four array values into an array of objects using JavaScript?

Looking to insert data from four array values into an array of objects in JavaScript? // Necessary input columnHeaders=['deviceName','Expected','Actual','Lost'] machine=['machine 1','machine 2&apo ...

Setting up ESM for Firebase functions: A step-by-step guide

Our server application needs to utilize the most recent ipfs-http-client as it is an authorized package for accessing IPFS. However, the project must switch to using ESM starting from v57.0.0. I have invested a significant amount of time into this and it h ...

What's the best way to integrate redux-persist into a TypeScript project?

Having some difficulty adding redux-persist to my React project (in typescript). The compilation is failing with the following error message: Could not find a declaration file for module 'redux-persist/lib/storage'. '.../WebstormProjects/c ...

"Techniques for extracting both the previous and current selections from a dropdown menu in Angular 2

How can I retrieve the previous value of a dropdown before selection using the OnChange event? <select class="form-control selectpicker selector" name="selectedQuestion1" [ngModel]="selectedQuestion1" (Onchange)="filterSecurityQuestions($event.t ...

The ListView is not updating correctly as expected

Currently, I am working on a project where I have a Page with a ListView that displays items from an ObservableArray of Expense objects. The issue I am facing is that when I scroll down, the amount property of some Expense rows is not being displayed. Howe ...

Attach [!hidden] to a dropdown menu choice using Angular 2

How can I implement a show/hide feature for a select box in Angular 2+? Here's what I have so far: <select> <option disabled selected>Flow progress</option> <option *ngFor='let flow of flows'>{{flow}}< ...

PhpStorm is unable to resolve the @ionic/angular module

I have encountered a peculiar issue with my Ionic v4 project. While the project runs smoothly, PhpStorm seems unable to locate my references to @ionic. https://i.stack.imgur.com/umFnj.png Interestingly, upon inspecting the code, I realized that it is act ...

Describe the TypeScript type for an object with constant keys

My query resembles the one found in this Typescript interface definition question, but has a slight variation. I am beginning with an object where the keys are constants: const KEYS = { KEY1: 'hello', KEY2: 'world' } as const; How ...