The extend keyword in TypeScript causing issues with type inference

Why is TypeScript showing an error in the code below?

type A = { kind: "a" }
type B = { kind: "b" }

const a = (a: A): void => undefined
const b = (b: B): void => undefined

const c = <C extends A | B>(c: C): void => (c.kind == "a" ? a(c) : b(c))

It appears that TypeScript is having trouble determining the type of c after checking c.kind == "a". Why is this happening?

The following variation seems to resolve the issue.

type A = { kind: "a" }
type B = { kind: "b" }
type C = A | B

const a = (a: A): void => undefined
const b = (b: B): void => undefined

const c = (c: C): void => (c.kind == "a" ? a(c) : b(c))

Answer №1

An interesting thing to note is that a typeguard will function properly on a parameter of a union type, but it will not work on a generic type parameter that extends a union. This limitation has been documented in an open issue, which may be addressed in the future.

To work around this issue, one approach is to utilize the non-generic version, which should suffice for simple scenarios like the example provided.

However, if your signature is more complex and involves using generic types in other contexts (such as conditional types or establishing relationships between parameters and return types), you can employ a function with multiple signatures – a public generic signature and a non-generic implementation signature:

function c<C extends A | B>(c: C): void
function c(c: A | B): void {
    return c.kind == "a" ? a(c) : b(c);
}

For further exploration and experimentation, check out this TypeScript 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

Creating a tsconfig.json file that aligns perfectly with your package.json and tsc command: a step-by-step

I've chosen to use TodoMvc Typescript-Angular as the starting point for my AngularJS project. Everything is working smoothly so far. Here's a breakdown of what I can do: To manage all dependencies, I simply run npm install or npm update based o ...

Troubleshooting: Vue.js component events not being detected in TypeScript

I'm encountering an issue with receiving events from a barcode reader, which I heavily referenced from a GitHub repository. The problem lies in the fact that the events emitted by the BarcodeScanner component are not being captured by the enclosing c ...

When using `type B = A`, B is represented as A. However, if `type B = A | A` is utilized, B appears as 'any'. What causes this change in representation?

import { C } from "https://example.com/type.d.ts"; type D = C | C Playground Upon hovering over D in both the TS Playground and VS Code, it will show as C when declared as type D = C, but display any when declared as type D = C | C. Even if C&a ...

The properties are not found in the type 'Observable<Todo[]>'

I'm currently following a YouTube tutorial and I've hit a roadblock trying to figure out where the error is originating from? Error Message: Type 'Observable' is missing properties such as length, pop, push, concat, and 25 more.ts(2740 ...

Proper method for typing the generics of DatePickerProps belonging to the DatePicker component in mui-x library

I have a component called CustomDatePicker which has been configured for localization as shown below: function CustomDatePicker(props: DatePickerProps<unknown> & React.RefAttributes<HTMLDivElement>) { return ( <StyledDatePicker ...

How is it possible that this is not causing a syntax or compile-time error?

Oops! I made a mistake and typed : instead of = on line 2 of this code snippet. Why does Typescript allow this error? Isn't colon supposed to indicate a known Type for a property declaration? I'm pretty sure there's a reason encoded in the ...

How to disable the onChange event in PrimeNG p-dropdown?

I'm currently utilizing PrimeNG's dropdown component. Each option in the list includes an icon that, when clicked, should trigger a specific method. Additionally, I need to execute another method when the onChange event of the dropdown is trigger ...

What steps can I take to ensure that the upper and left sections of a modal dialog remain accessible even when the size is reduced to the point of overflow?

One issue I'm facing is with a fixed-size modal dialog where part of the content gets cut off and becomes inaccessible when the window shrinks to cause an overflow. More specifically, when the window is narrowed horizontally, the left side is cut off ...

When working with Typescript and Vue.js, it's important to ensure that properties are initialized before

Check out the following code snippet: export default class PrimitiveLink extends Vue { style = { // Reset display: 'inline-block', textDecoration: 'none', outline: 'none', // Theme ...this.themeStyle ...

Angular checkboxes not updating with current values when submitted

I have defined a static array in TypeScript like this: permissions: any[] = [ { permission: "Read", enabled: true }, { permission: "Write", enabled: false }, { permission: "Delete", enabled: false }, { permission: "Edit", enabled: true } ...

Next.js TypeScript throws an error stating that the object 'window' is not defined

When trying to declare an audio context, I encountered an error stating that window is undefined. I attempted declaring declare const window :any above window.Context, but the issue persists. Does anyone have a solution for this problem? window.AudioCont ...

Error TS2694 is being caused by Electron Typescript Material-UI withStyles because the namespace "".../node_modules/csstype/index"" does not have an exported member called 'FontFace'

While I am experienced with Material-UI, I am relatively new to Electron and using React, TypeScript, and Material-UI together. Recently, I encountered an error while attempting to create an electron boilerplate code for future project initialization. Init ...

The Validation Library known as 'Yup' encounters compilation issues with TypeScript

After deciding to utilize the Yup library for form validation in my project, I encountered a persistent and confusing library error each time I tried to install it. This issue has been plaguing me despite numerous attempts to troubleshoot. Any suggestions ...

Is there a way to make Typescript accept dot notation?

Is there a way to suppress the compile time error in Typescript when using dot notation to access a property that the compiler doesn't know about? Even though using bracket notation works, dot notation would be much more readable in my specific case. ...

Using Vue-router and Typescript with beforeEnter guard - utilizing validated data techniques

As I utilize Vue along with vue-router and typescript, a common scenario arises where a single page is dedicated to displaying a Photo component. A route includes a beforeEnter guard that checks my store to verify the existence of the requested photo. ...

Utilizing vue-property-decorator: Customizing the attributes of @Emit

After seeing the @Emit feature, I checked out the example on GitHub. import { Vue, Component, Emit } from 'vue-property-decorator' @Component export default class YourComponent extends Vue { count = 0 @Emit() addToCount(n ...

Error in Cordova integration with Razorpay [RazorPayCheckout not found]

I'm encountering an issue where I'm getting a "RazorPayCheckout is not defined" error. I've searched on StackOverflow but couldn't find any helpful answers. Can someone please assist me with this? Thank you in advance. app.component.ht ...

Custom Joi middleware in Express v4 is failing to pass the Request, Response, and Next objects

I am currently in the process of developing a unique middleware function to work with Joi that will be placed on my routes for validating a Joi schema. In the past, I have created middlewares for JWT validation without passing any parameters, and they wor ...

What is the best way to reset the testing subject between test cases using Jest and TypeScript?

I'm currently utilizing typescript alongside jest for unit testing. My goal is to create a simple unit test, but it consistently fails no matter what I try. Below is the snippet of code in question: // initialize.ts let initialized = false; let secre ...

What is the reason for the manual update of a view when copying an object's attributes into another object, as opposed to using Object.assign()?

In my application, I have a parent component called 'EmployeeComponent' that is responsible for displaying a list of employees. Additionally, there is a child component named 'EmployeeDetailComponent' which displays the details of the s ...