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's definition is known or unknown, I would expect them to be uniform. Why is there a discrepancy?

Answer №1

Based on information from microsoft/TypeScript#54630, particularly highlighted in this statement by the TS team dev lead:

No definitive assurances exist regarding the behavior when an error type is present in your program.

If you attempt to import something that cannot be located, a compiler error will occur:

import { A } from "https://example.com/type.d.ts"; // error!
// -------------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Cannot find module 'https://example.com/type.d.ts' or its corresponding type declarations.

The references to the missing item may be displayed as the any type, due to various reasons.

The hover displays "any" as there is no better alternative at hand. While differentiation is conceivable, such details tend not to persist in programs for extended periods.

This clarifies why instances of any are observed sometimes.


Regarding the display of A rather than any after transition from

type B = A | A
//   ^? type B = any

to

type C = A;
//   ^? type C = A

no consistent and documented rule governs how these types are exhibited. If A occasionally appears as any, it falls under the discretion of the compiler to determine the presentation. Even without errors, this dichotomy would still arise:

type D = { a: string };

type E = D;
//   ^? type E = { a: string; }

type F = D[];
//   ^? type F = D[];

Here, type D serves as an obvious alias for {a: string}. Certain uses of D resolve to {a: string}, while some retain the alias itself.

These distinctions concern solely the visual representation of the type, without impacting the underlying nature of the identities. Presently, developers lack a supported method to dictate the preferred appearance of a type when displayed. Several open feature requests like microsoft/TypeScript#28508, microsoft/TypeScript#31940, and microsoft/TypeScript#45954 could potentially alter this scenario, but currently, it is not inherent to the language. The compiler employs heuristics to determine the type for display; although effective in diverse scenarios, they cannot cater to all requirements simultaneously. For every individual preferring D to show as {a: string}, there exists an opposing viewpoint advocating for maintaining it as D, both with valid reasoning, perceiving their preference as enhancing consistency. More control over this aspect by developers would be advantageous; lacking that, the outcome remains unpredictable.

Hence, with regards to the discrepancy between seeing any for A | A but A for A, pinpointing a specific reason entails delving into TypeScript compiler code alongside documentation detailing the accountable components. However, such insights may not yield significant revelations, subject to alterations in future TypeScript versions. When two types are identical, the compiler retains complete authority over determining which manifestation to exhibit and when.

Access the Playground link for the code snippet

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

Using TypeScript and Node.js with Express; I encountered an issue where it was not possible to set a class property of a controller using

I have a Node application using Express that incorporates TypeScript with Babel. Recently, I attempted to create a UserController which includes a private property called _user: User and initialize it within the class constructor. However, every time I ru ...

How can I retrieve query parameters in the Server app directory of Next.js 13 using a function?

I am looking to retrieve a query token from localhost/get/point?token=hello. import { NextResponse } from 'next/server' import base64url from 'base64url' type Params = { token: string } export async function GET(req: Request, contex ...

Typescript - ensure only one specific value is in an array of length N

Is there a way to require the 'foo' literal, while allowing the array to have any shape (i.e. not using an X-length tuple with pre-defined positions)? type requireFoo = ??? const works: requireFoo = ['bar','foo'] //This shoul ...

Ways to utilize multiple tsconfig files within VS Code

My project structure in Visual Studio Code is fairly common with a client, server, and shared directory setup: ├── client/ │ ├── tsconfig.json ├── shared/ ├── server/ │ ├── tsconfig.json ├── project.json The tw ...

The specified type does not meet the constraint as it lacks the required index signature

I'm currently working on refactoring a TypeScript project that utilizes React Hooks. While I have some knowledge of TypeScript, I am still more of a beginner than an expert. My main goal is to create reusable code for this project through the use of ...

Using a Jasmine spy to monitor an exported function in NodeJS

I've encountered difficulties when trying to spy on an exported function in a NodeJS (v9.6.1) application using Jasmine. The app is developed in TypeScript, transpiled with tsc into a dist folder for execution as JavaScript. Application Within my p ...

What is causing the transpiler to not be triggered by the code change?

My current project involves using a TypeScript backend for a Dialogflow application with fulfillment. I initially used a preconfigured project template and didn't delve into the details. I work in VS Code and never explicitly build my code. Instead, ...

Tips for transforming or changing Partial<T> into T

I have a variable named Partial<T> in my coding project. returnPartial(): Partial<T> {} proceed(param T) {} //<-- the provided input parameter will always be of type T in this function and cannot be changed let object = this.returnPartial( ...

Incorporate dynamic HTML snippets into the DOM with Angular 4

Looking to populate an unordered list element <ul> with small, straightforward snippets from my JavaScript. Just basic lines like <li>Label: Text</li>. Using the ViewContainerRef.createComponent(ItemComponent) method to create a new comp ...

Retrieve the attribute from a TypeScript union data type

Here is the structure that I am working with: export interface VendorState extends PaginationViewModel { vendors: CategoryVendorCommand[] | CategoryVendorCommand; } This is my model: export interface CategoryVendorCommand { id: string; name: str ...

Exporting stylesheets in React allows developers to separate

I am trying to figure out how to create an external stylesheet using MaterialUI's 'makeStyles' and 'createStyles', similar to what can be done in React Native. I'm not sure where to start with this. export const useStyles = m ...

Transform a nested array of objects into a distinct set of objects based on the data in JavaScript or TypeScript

I have a unique situation where I am dealing with a double nested array of objects, and I need to restructure it into a specific array format to better align with my table structure. Here are the current objects I'm working with and the desired resul ...

The functionality of Angular 6 Material Nested Tree is disrupted when attempting to use dynamic data

In Angular 6, I am utilizing mat-tree along with mat-nested-tree-node. My objective is to dynamically load the data when the user toggles the expand icon. Attempting to apply the dynamic data concept from the Flat Tree example provided in Material Example ...

Combine the selected values of two dropdowns and display the result in an input field using Angular

I am working on a component that consists of 2 dropdowns. Below is the HTML code snippet for this component: <div class="form-group"> <label>{{l("RoomType")}}</label> <p-dropdown [disabled] = "!roomTypes.length" [options]= ...

In TypeScript, if all the keys in an interface are optional, then not reporting an error when an unexpected field is provided

Why doesn't TypeScript report an error when an unexpected field is provided in an interface where all keys are optional? Here is the code snippet: // This is an interface which all the key is optional interface AxiosRequestConfig { url?: string; m ...

The value of type 'X' cannot be assigned to type 'Y' or 'undefined'

In my code, there is a component that requires a prop with an enum value: export enum AType { some = "SOME", word = "WORD", } const MyComponent = (arg: AType) => {} When I try calling this component like so: <MyComponent ar ...

Is there a way to utilize an AXIOS GET response from one component in a different component?

I'm having trouble getting my answer from App.tsx, as I keep getting an error saying data.map is not a function. Can anyone offer some assistance? App.tsx import React, {useState} from 'react'; import axios from "axios"; import {g ...

Using custom types for prop passing in Next.js with TypeScript

After making a http call, I obtain an array containing JSON data. This data is then assigned to a type called Service. type Service = { id?: string; name?: string; description?: string; }; The api call is made in getServerSideProps and the Service type is ...

When utilizing React and Expressjs to upload a file through REST, the request seems to stall indefinitely

Seeking assistance with a simple React page containing a form for file selection and submission. The file is uploaded to the server via a POST request using axios. Here's the code snippet for the client-side: import React, { useState } from "reac ...

What is the best way to generate a dynamically interpolated string in JavaScript?

I'm currently developing a reusable UI component and am exploring options to allow the user of this component to provide their own template for a specific section within it. Utilizing TypeScript, I have been experimenting with string interpolation as ...