When TypeScript's Exclude<UnionOfTypes, Interface> is used, the resulting type is always "never"

What causes Exclude<A,B> to resolve to the never type in the code snippet below? Shouldn't the typescript compiler be able to infer (through static analysis) that A and B are extending Parent, leading to Exclude<Choices, Parent> resolving to type C?

interface Parent {}

interface A extends Parent {}
interface B extends Parent {}
interface C {}

type Choices = A | B | C

type Test = Exclude<Choices, Parent> // = type "never"???

const c: C = {}
const d: Test = c // Type 'C' is not assignable to type 'never'

One possible workaround is to manually set Parent = A | B, but the necessity of this step remains unclear.

Answer №1

The reason behind this is due to TypeScript's duck typing. In this case, because both C and Parent are of the same interface, C can be assigned to Parent.

This example illustrates this concept:

const c: C = {};
const p: Parent = c;

Even though C doesn't explicitly declare that it extends Parent, TypeScript still recognizes C as a type of Parent.

If you want to ensure this behavior, simply include a property in Parent that is not present in C.

interface Parent { foo: string }

interface A extends Parent {}
interface B extends Parent {}
interface C {}

type Choices = A | B | C

type Test = Exclude<Choices, Parent> // = type C

const c: C = {}
const d: Test = c // works!

Answer №2

I have developed a unique type tool in the following manner

// This tool functions as the inverse of [exclude].
type Contains<T, U> = U extends T ? U : never;

Here is an example of how to use it

    type X = {
      x : number;
      xx:number;
      xxx:number;
    }

    type Y = {
      y : number;
    }

    type Z = {
      z : number;
    }

    type W = {
      w : number;
    }


    // In this scenario, we are checking for the type X
    type Element_ContainsX = Contains<{
      x : number;
    }, X|Y|Z|W>

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

Update current properties of objects

I'm feeling like I'm going crazy and could really use some assistance. My predicament involves a function that looks like this: private generateTimeObject(firstObject: someInterface, secondObject?: someInterface) { let firstTime; let secondTi ...

Starting a nested JSON structure with TypeScript and Angular 7

I'm encountering an error when attempting to make a POST request by sending an object TypeError: Can not set property 'ItemCode' of undefined My setup involves Angular 7 and Typescript Here is my initial JSON: objEnvio:any = <an ...

The `react-router-dom` in React consistently displays the `NotFound` page, but strangely, the active class for the home page does not get

Currently, I am utilizing "react-router-dom": "^6.4.1" in my application and encountering two main issues: Upon navigating to another page, the home page retains the active class, resulting in both the new page and the home page disp ...

Elevate your Material UI Avatar with an added level of

Attempting to give a MUI Avatar component some elevation or shadow according to the documentation provided here. <Avatar alt="Cindy Baker" src="/static/images/avatar/3.jpg" /> Enclosing the Avatar within a paper or Card element increases the size o ...

Is it necessary to set up webpack for ES6 support?

I am encountering an issue with my Angular application that has a .tsconfig file set to target ES6. { "compileOnSave": false, "compilerOptions": { "allowJs": true, "baseUrl": "./", "outDir": "./dist/out-tsc", "sourceMap": true, "de ...

Creating a customizable stepper component that can be easily reused with Angular 6 Material

With Angular material stepper, my objective is to customize steps for reusing the stepper component. I am dynamically loading steps, so depending on the requirement, I need to load the stepper in different components. The scenarios I have are as follows: ...

Exploring the power of nested components within Angular 2

I am encountering an issue with a module that contains several components, where Angular is unable to locate the component when using the directive syntax in the template. The error message I receive states: 'test-cell-map' is not a known elemen ...

Learn how to trigger an event or API call in Angular 8 when the browser is closed with the help of HostListener

I am facing the challenge of calling a simple websocket closure API when the browser is closed in my project. I attempted to utilize HostListener, but unfortunately it did not work as expected. You can find the code snippet below: https://stackblitz.com/ ...

Trouble with updating data in Angular 8 table

In Angular 8, I have created a table using angular material and AWS Lambda as the backend. The table includes a multi-select dropdown where users can choose values and click on a "Generate" button to add a new row with a timestamp and selected values displ ...

Creating table structure dynamically using Node.js

I'm attempting to automatically create a table using nodejs "@google-cloud/bigquery": "^3.0.0" with the following approach: const bigqueryClient = new BigQuery(); schema = `driverId:string, passengerIds:(repeated string), pickedUp:(repeated s ...

Struggling with TypeScript and JsObservable? Let us assist you!

Having previous experience with JSRender, JSViews, and JSObservables, I recently embarked on a new project using TypeScript. Unfortunately, I am struggling to understand how to properly utilize TypeScript in my project, especially when it comes to referenc ...

Using useState as props in typescript

Let's imagine a situation where I have a main component with two smaller components: const MainComponent = () => { const [myValue, setMyValue] = useState(false) return ( <> <ChildComponent1 value={myValue} setValue={set ...

Obtain the function's return type without actually executing the function

Consider the following TypeScript function: export const foo = function(){ return { a: 1, b: true, c: 'bar' } }; If I were to import this function into another file: import {foo} from './foobar'; Is there a me ...

Having trouble getting the Typescript overload arrow function to function properly

(I am implementing strict null checks) The arrow function I have includes overloaded types: type INumberConverter = { (value: number): number; (value: null): null; }; const decimalToPercent: INumberConverter = (value: number | nul ...

Solutions for resolving the issue of not being able to load images when using merged-images in JavaScript

I have a base64 image here and it has already been converted. data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxQSEhUTEhQWFhUXGBoaGBgYGBcXGhgXGBgYGhgbHhoZHiggGholHhgYITEhJSkrLi4uHR8zODMtNygtLisBCgoKDg0OGhAQGi0lICUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0 ...

Struggling to retrieve object values through useContext? Consider implementing useReducer in conjunction with useContext for more efficient state management

I'm facing an issue while trying to access my dispatch functions and states from the useContext. Strangely, when I attempt to destructure the context object in order to access them directly, I receive an error message stating that it does not exist (E ...

Performing Jasmine unit testing on a component that relies on data from a service, which itself retrieves data from another service within an Angular 2+ application

Attempting to implement unit testing for a service using httpmock has been challenging. The service in question utilizes a method to make http get calls, but I have encountered difficulties in writing the test cases. saveservice.service.ts -- file const ...

Angular 4 with Typescript allows for the quick and easy deletion of multiple selected rows

I am currently working on an application where I need to create a function that will delete the selected checkboxes from an array. I have managed to log the number of checkboxes that are selected, but I am struggling to retrieve the index numbers of these ...

The power of absolute paths in React Native 0.72 with TypeScript

Hi everyone! I'm currently having some difficulty setting absolute paths in react native. I tried using babel-plugin-module-resolver, as well as configuring 'tsconfig.json' and 'babel.config.js' as shown below. Interestingly, VS Co ...

Total the values of several items within the array

Here is the data I currently have: const arrayA = [{name:'a', amount: 10, serviceId: '23a', test:'SUCCESS'}, {name:'a', amount: 9, test:'FAIL'}, {name:'b', amount: ...