What is the standard approach for indicating the lack of a specific attribute?

Is there a standardized way to specify that a specific property must definitely NOT appear on an object? I have come up with a method like this:

type NoValue<T extends { value?: never, [key: string]: unknown }> = T
type Foo = NoValue<{}> // This type checks
type Bar = NoValue<{name: string}> // This also type checks
type Baz = NoValue<{ value: string }> // This will throw an error, as expected

However, I'm unsure if this method covers all possible scenarios. Is there an established standard approach for achieving this?

Answer №1

In TypeScript, there is no definitive method to prevent specific string literals from being used as known property keys of an object type. While there is no official feature that directly addresses this issue, the approach you are taking is considered the conventional method.

One workaround is to utilize an optional property that allows for a property to be absent, with a type of the impossible `never` type that cannot typically have a value. The recommended way to achieve `{value?: never}` is by creating an object without a `value` property. To ensure this is the sole requirement, you can include an index signature `{[k: string]: any}`. It is essential to use the `any` type instead of `unknown` as `any` permits interface types without explicit index signatures, while `unknown` does not.

type NoValue<T extends { value?: never, [key: string]: any }> = T

or

function noValue<T extends { value?: never, [key: string]: any }>(t: T) { }

noValue({}); // valid
noValue({ a: 123 }); // valid
noValue({ a: 123, value: 456 }); // error!

Despite this approach, there are some edge cases to consider. One common scenario is

noValue({ value: undefined }); // usually valid

where `undefined` is considered an acceptable property type for optional properties. Enabling the `--exactOptionalPropertyTypes` compiler option can prevent this behavior, but it adds strictness not included in the standard `--strict` suite of options. Many users find `--exactOptionalPropertyTypes` cumbersome to use.


A less frequent edge case is the possibility of obtaining a value of type `never` when the compiler is confident that an exception will be thrown before reaching that point in runtime. For instance:

const v = {
    get value(): never {
        throw new Error("I DON'T LIKE YOU")
    }
};
noValue(v); // valid

In this scenario, the compiler recognizes `v` as being of type `{value: never}` because an exception will occur if `v.value` is evaluated. This situation is rare but technically feasible.


Ultimately, there are limitations to preventing the compiler from losing track of whether a value has a `value` property. The compiler can always widen a type to a supertype and treat optional properties as assignable to a type without a known property. As a result, the best approach in TypeScript is to discourage rather than prohibit an object property.

Link to Playground with code

Answer №2

type NoValuePossible = { [K: keyof any]: never };

const valueExists: {} = { bar: 42 };

const objCanBeAssignedTo: NoValuePossible = valueExists;

// no error will be thrown

It is impossible to achieve.

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

Testing the Angular router-outlet using Jasmine

When testing web-app navigation using Jasmine spec with RouterTestingModule, I am facing challenges with nested fixture.whenStable().then(() => {}). For instance: After clicking on multiple links where the router-outlet changes the displayed component ...

Creating a versatile function in TypeScript for performing the OR operation: A step-by-step guide

Is there a way in TypeScript to create a function that can perform an OR operation for any number of arguments passed? I currently have a function that works for 2 arguments. However, I need to make it work for any number of arguments. export const perfo ...

Error: The class constructor [] must be called with the 'new' keyword when creating instances in a Vite project

I encountered an issue in my small Vue 3 project set up with Vite where I received the error message Class constructor XX cannot be invoked without 'new'. After researching online, it seems that this problem typically arises when a transpiled cla ...

Global error handling fails to catch re-thrown HTTP errors in rxjs throwError scenario

Purpose: Implementing a global error handler for server errors and application errors generated in Typescript code. Approach: Utilizing a custom ErrorHandler from a library project within the same workspace. The library structure is as follows: https://i ...

Guide on executing .ts script file and building angular 5 with NPM

I am facing an issue with running a file that has a .ts extension before executing npm run build to build my Angular 5 project. package.json "scripts": { "ng": "ng", "start": "ng serve", "compile": "npm-run-all myts build", "myts": "ts-no ...

What location is the optimal choice for documenting logs at a debugging level?

My team and I have been deeply contemplating the best location for writing a debug-level log during our development process. We are utilizing winston in conjunction with winston-daily-rotate-file to separate out different aspects of logging, as well as ne ...

Implementing Limited Results in Redis FT.SEARCH with TypeScript

Snippet of code: client.ft.SEARCH('license-index-json',"@\\$\\" + ".reservedForApplicationName:GSTest",{ LIMIT: { from: 0, to: 1 } }) Error message: An error occurred when trying t ...

Experimenting with a file system library function using Jest and Typescript alongside a placeholder function

When attempting to test a library function that uses the fs module, I received assistance in this question on Stack Overflow. The feedback suggested avoiding mocks for better testing, an approach I agreed with @unional. I am now facing a similar challenge ...

Executing a series of HTTP requests sequentially using Angular 5

I need some guidance on sending an array of HTTP requests in sequential order within my application. Here are the details: Application Entities : Location - an entity with attributes: FanZone fanZone, and List<LocationAdministrator> locationAdmins ...

Transforming JSON keys in Angular

As a newcomer to angular and API integration, I am facing an issue with ngCharts in my project. The chart specifically requires the keys names in JSON to be "value" and "name", but the API I am using provides keys named "count" and "label". Is there a way ...

Having trouble with the Angular Material component? The element 'mat-option' is not recognized

I am having trouble with implementing an Angular Material component. The component is not functioning properly, and I received the following error message: Uncaught Error: Template parse errors: 'mat-option' is not a known element: // ... I sus ...

Sharing properties between components

While this topic has been discussed extensively, I am still struggling with my specific example. In my setup, I have a react-select component nested within another component, which is then part of the larger App component. SubjectSelect.tsx export default ...

flickering effect problem

What could be causing the issue where [@fadeInOut] only works on the initial page load when toggling isExpanded to hide or show content? Due to [@fadeInOut], the content stops showing up. Any thoughts on what might be causing this and any alternative solut ...

SonarQube alerting you to "Eliminate this unnecessary casting"

Can someone help me understand why SonarQube is flagging this error and suggest a resolution? The unnecessary cast should be removed. Promise.all([ this.customerViewCmr4tProvider.getData(activeNumber), this.customerBillManagementProvider.getData(ind ...

What steps are involved in updating the default value in ngx-daterangepicker-material?

Is there a way to change the default value of gx-daterangepicker-material from yesterday to the last 7 days? If so, how can this be achieved? Here is the code snippet: export class CustomRangesComponent implements OnInit { selected: any; alwaysShowCalenda ...

Angular 4 prohibits certain special characters and the number zero

Currently, I am a beginner in Angular 4 and I am working on learning how to search for data from a text box. However, whenever I input special characters like "%" in my code, it triggers an error leading to a crash in my application. Is there any effectiv ...

Why is it that in Angular, console.log(11) is displayed before console.log(1)?

Can someone help me understand why my simple submit method is printing Console.log(11) before Console.log(1)? I'm confused about the order of execution. submit(value) { this.secServise.getUserById(this.currentUser.mgId).subscribe( uAddrs => { ...

Using Angular and Typescript to implement mathematical formulas involving date object subtraction

I need help converting the following Excel formula to Typescript. I keep running into an error that says 'The left-hand and right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type'. Can anyon ...

What is the method for utilizing a class variable without assigning a value to it initially

class testClass { student: { name: string, age: number } constructor(options?: any) { this.student = { name: '', age: 0 }; } setStudent(name:string, age:number) { this.student.name ...

Creating a key/value pair type in Typescript that mirrors the shape of an object within an array: How to do it?

Here is the data that I have: const pets = [ { type: 'cat', name: 'penny' }, { type: 'dog', name: 'Fido' }, { type: 'fish', name: 'Nemo' } ]; In order for a pe ...