Combining types with additional features

Is it possible to configure the TypeScript compiler to generate an error when a function is called with an argument that can belong to both cases in a union type? For example:

interface Name {
  name: string
}

interface Email {
  email: string
}

type NameOrEmail = Name | Email

function print(p: NameOrEmail) {
 console.log(p)
}

print({name: 'alice'}) // This works fine
print({email: 'alice'}) // This also works
print({email: 'alice', name: 'alice'}) // Currently this works, but I want it to trigger an error
print({email: 'alice', age: 33}) // This should not work

Answer №1

If you want to hide the implementation details of a method in your code, you can achieve that using method overloading:

interface Person {
  name: string
}

interface Contact {
  email: string
}

function displayInfo(p: Person): void;
function displayInfo(c: Contact): void;
function displayInfo(pc: Person | Contact) {
  console.log(pc);
}

displayInfo({name: 'Alice'}) // This works fine
displayInfo({email: 'alice@example.com'}) // This also works fine
displayInfo({email: 'alice@example.com', name: 'Alice'}) // Should not work, but it does
displayInfo({email: 'alice@example.com', age: 30}) // Doesn't work as intended

By employing this approach, the actual signature of the method implementation is kept hidden from the rest of your code.

Demo

Edit:

In strict mode, it is necessary for overloaded signatures to specify a return type. While the return type of the implementation can still be inferable as long as it aligns with the specified return types in the visible signatures.

Answer №3

When checking for excess properties on object literals within union types, the presence of a property on any member will not trigger an error. In cases where the interfaces do not have conflicting properties, the object literal with excess properties can be assigned to either member of the union, making it a valid assignment.

To avoid this behavior, one must make the interfaces incompatible by introducing a field with a string literal type and different values in each interface:

interface FirstName {
    type: 'first'
    name: string
}

interface LastName {
    type: 'last'
    name: string
}

type FullName = FirstName | LastName

function display(p: FullName) {
    console.log(p)
}

display({ name: 'Alice', type: 'first' }) // Succeeds
display({ name: 'Smith', type: 'last' }) // Succeeds
display({ name: 'Smith', age: 25, type: 'last' }) // Will fail 
display({ name: 'Alice', lastName: 'Smith', type: 'first' }) // Does not work

Answer №4

Here is a different example:

export type CombinationType = TypeA | TypeB;

export interface TypeA {
    value: number;
}

export interface TypeB {
    info: string;
}

export const combinationType: CombinationType = {
    value: 98765,
    info: [{ bar: 'asdfg' }, { jkl: 'poiuy' }], // <-- this is acceptable for TypeScript!
};

Here is the referral 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

Having trouble initialising an array of objects in TypeScript? (TS1109: Expression expected)

While working on my project, I encountered a problem when trying to create an array of objects: Error TS1110: Type expected Error TS1109: Expression expected https://i.sstatic.net/Y5qb8.png This is how my array is structured: export let COUNTRIES: A ...

index signature in TypeScript is an optional feature

Is it possible to create a type with optional namespaces in TypeScript? export interface NodesState { attr1: number; attr2: number; attr3: number; } The goal is to allow users to namespace the type like this: { namespace1: { attr1: 100, ...

Ways to simulate objects in jest

I'm facing an issue while trying to mock a function of an object using Jest and Typescript. Below is a concise version of my code: // myModule.ts export const Foo = { doSomething: () => { // ... does something console.log('original ...

Using TypeScript generics to define function parameters

I'm currently working on opening a typescript method that utilizes generics. The scenario involves an object with different methods, each with specified types for function parameters. const emailTypes = { confirmEmail: generateConfirmEmailOptions, / ...

`Can incompatible Typescript types be allowed for assignment?`

Currently, I am faced with the challenge of sharing type definitions between my server and front-end. These definitions are stored in a separate npm package that both installations utilize. The issue arises on the front-end where variables containing Objec ...

The type 'undefined' cannot be assigned to the type 'string | Buffer | { key: string | Buffer; passphrase: string; } | GetPublicKeyOrSecret'

Verification Code for JWT This function is used to verify a jwt using typescript. public verify( token: string, secretOrPublicKey?: string | Buffer, options?: jwt.VerifyOptions ): Promise<object | string> { if (!secretOrPublicKey) { ...

Learn the proper way to write onClick in tsx with Vue 2.7.13

current version of vue is 2.7.13 Although it supports jsx, I encounter a type error when using onClick event handling. The type '(event: MouseEvent) => Promise<void>' cannot be assigned to type 'MouseEvent' Is there a correct ...

What setting should I adjust in order to modify the color in question?

Looking to Customize Radar Chart Highlighted Line Colors I am currently working on a Radar Chart and I am trying to figure out which property needs to be edited in order to change the color of the highlighted lines. I have already attempted to modify the ...

What is the process through which Typescript determines the property types of union types?

I am implementing a unique set of types to enable angular form typing: import { FormArray, FormControl, FormGroup } from '@angular/forms'; export type DeepFormArray<T, U extends boolean | undefined = undefined> = T extends Array<any> ...

Trying to enter the function, but it exits without executing

I'm facing an issue with my function that involves making multiple calls to an observer. I need the function to wait until all the calls are complete before returning. I attempted putting the return statement inside the subscribe method, but it result ...

Tips on modifying the selected type key name through Pick?

I currently have this structure: type Product = { name: string } and I am looking to extract the name property and use it in a different type declaration like so: type NewProduct = Pick<Product, 'name'> Now, I want to rename name as new ...

Leveraging TypeScript 2.1 and above with extended tsconfig configurations

Recently, I have been experimenting with the new extends feature in the tsconfig.json file that allows developers to create a base configuration which other modules can extend or modify. Although it is functional, it is not working as anticipated. Strange ...

The object in an Angular 11 REACTIVE FORM may be null

I am looking to incorporate a reactive form validation system in my application, and I want to display error messages based on the specific error. However, I am encountering an error that says: object is possibly 'null'. signup.component.html &l ...

Include a Polyfill in craco, implementing a fallback for 'resolve.fallback'

I'm encountering an issue: If you need to use a polyfill, follow these steps: - include a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }' - install 'path-browserify' If you prefer n ...

Enhance Your NestJS Experience: Using Interceptors for Mapping and Error Handling

I'm looking for a NestJS interceptor that can log requests in all scenarios, including both successful executions and errors. Below is an example implementation: public intercept(context: ExecutionContext, next: CallHandler): Observable<any> { ...

Angular 8: How to Filter an Array of Objects Using Multiple Conditions

I am faced with the following scenario where I need to filter an array of objects based on lineId, subFamily, and status. My current code successfully filters based on lineId, but now I also need to include a condition for subFamilyId. I have two specifi ...

What sets typescript apart when using a getter versus a regular function?

Imagine having a class with two methods declared for exclusive use within that class. // 1. private get something() { return 0; } // 2. private getSomething() { return 0; } While I am familiar with getters and setters, I'm intrigued to know if ther ...

Merging Type-GraphQL and Typegoose through a Variety of Decorators

Using a combination of Type-GraphQl and Typegoose, I aim to streamline my data definitions by consolidating them into one source for both GraphQL schemas and Mongoose queries. Is it feasible to merge the two libraries in a way that allows me to describe bo ...

Tips for effectively highlighting search text within HTML content without causing any issues

I am in search of a solution that can assist me in searching for specific terms within an HTML string while also highlighting them. I have the ability to remove the HTML content from the string, but this poses the problem of losing the context of the origi ...

Extracting data from an array using Angular

Currently, I am developing an Angular application that involves handling an array structured like the one below. [ { Code: "123", Details:[ { Id: "1", Name: "Gary" }, { ...