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

Struggling to implement a singleton service in Angular as per the documentation provided

I have implemented a service in Angular that I want to be a singleton. Following the guidelines provided in the official documentation, I have set the providedIn property to "root" as shown below: @Injectable({ providedIn: "root" }) export class SecuritySe ...

The Static Interface Binding in TypeScript

I have inquired about how to extend the static functionality of existing objects in JavaScript (using TypeScript). In all examples provided here, I am utilizing Object The code below showcases a polyfill definition for ECMAScript's Object.is function ...

Having trouble utilizing Vue3 methods while utilizing the `<script setup lang="ts">` syntax

Looking to incorporate Vue into a non-Vue Class using the Composition API for a Chrome Extension project where having the entire thing as a Vue App doesn't make sense. The Vue Instance is being instantiated in the usual manner and then injected into ...

Encountering an error while compiling the Angular 8 app: "expected ':' but got error TS1005"

As I work on developing an Angular 8 application through a tutorial, I find myself facing a challenge in my header component. Specifically, I am looking to display the email address of the currently logged-in user within this component. The code snippet fr ...

Incorporating AngularFire2 in the latest Angular 11.0.5 framework

I have been attempting to utilize Firebase as a database for my angular application. Following the guidance provided in these instructions (located on the official developers Github page), I first installed npm install angularfire2 firebase --save in my p ...

Connecting multiple TypeScript files to a single template file with Angular: A comprehensive guide

Imagine you are working with a typescript file similar to the one below: @Component({ selector: 'app-product-alerts', templateUrl: './product-alerts.component.html', styleUrls: ['./product-alerts.component.css'] }) expo ...

Updating state in React without providing a key prop is a common issue, especially when

Currently, I am working on implementing a Radio Group where I want the radio button's checked value to update when another button is clicked. In the example provided below, it seems that the desired effect can only be achieved using the "key" prop. Is ...

Angular correctly displaying specific array items within button elements

I am facing an issue with my dashboard where I have 4 items in an array and 4 buttons on display. My goal is to assign each item with a specific button, but currently, it shows 4 buttons for each "hero" resulting in a total of 16 buttons. I have tried usin ...

Are there any methods for utilizing the Angular/flex-layout API within a TypeScript file in an Angular 11 project?

When working with Angular Material, the Angular Flex Layout proves to be quite beneficial. Is there a way to access the flex layout API within a TypeScript file? For instance, can we retrieve MediaQueries values from this link in a TypeScript file? breakp ...

Angular update row and save data to an array

When comparing the data of an edited row with the row just below it, I encounter a specific scenario. In a table containing 5 rows, as I edit records from top to bottom using the provided code snippet, I am able to store the values in an array. The most re ...

One-of-a-kind npm module for typescript

As part of my project, I am enhancing an existing library to make it compatible with TypeScript. To showcase this modification, I have condensed it into a succinct Minimal working example The specified requirements To ensure backward compatibility, the li ...

Sending selected IDs from the JSON data

In my project, there is a JSON file named "workers" which contains information about all the workers. I have created a select component to display the names of the workers like this: Currently, I am selecting some workers from the list and sending their n ...

strictBindCallApply causing issues when working with generic parameters

Take a look at this slightly contrived code snippet: export function evaluate<T>(this: { value: T }) { return this.value; } class SomeClass { value: ''; constructor() { const result = evaluate.call(this); } } You might notice ...

Tips for generating a fixed-length array from multiple arrays with different lengths, focusing on selecting items from each array according to their significance

In order to create a quiz, I am looking to extract 'questions' from various 'topic' arrays. These topics are selected based on the user's preference and are used to populate a question bank for a 20-question quiz. The topics rated ...

Learn how to retrieve data from the console and display it in HTML using Angular 4

Need help fetching data inside Angular4 HTML from ts variable. Currently only able to retrieve 2 data points outside the loop. Can anyone assist with pulling data inside Angular4? HTML: <tr *ngFor="let accept of accepts"> ...

Using an external npm module in TypeScript can result in the tsc output directory being modified

In my TypeScript project, I have set up the build process to generate JavaScript files in the ./src/ directory. Everything works smoothly when building against existing npm modules, such as Angular 2 imports. However, I encountered a strange issue when I ...

Manufacturing TypeScript classes that are returned by a factory

Developed a custom library that generates classes based on input data and integrates them into a main class. To enhance code maintainability and readability, the logic for generating classes has been extracted into a separate file that exports a factory f ...

The issue with loading scripts in a ReactJS NextJS app is related to the inline condition not working

I'm having trouble with an inline condition for loading scripts. The condition seems to be working because the tag is displaying text, but when it comes to scripts, it doesn't work. How can I resolve this issue? const cookie = new Cookies().get ...

Angular Universal causing issues with updating the DOM component

@Component({ selector: 'mh-feature-popup', template: ` <div class="full"> <div> <div class="container-fluid" [@featurepop]="state"> <div class="row"> <div class="col-xs-12 col-md-4 col-md-offse ...

Discover the steps to initiate Firefox in Incognito Mode using NodeJS and Selenium!

Can anyone help me figure out how to launch Firefox in private mode using TypeScript? I have attempted the following code but it doesn't seem to work: static async LaunchFirefoxInPrivateMode():Promise<WebDriver> { //Setting up firefox capab ...