Using the typescript infer feature does not function properly when dealing with arrays

My TypeScript code is causing some unexpected results:

const myObject = {
  foo: ['a', 'b', 'c']
}

type MyType = typeof myObject.foo extends [...infer Content] ? string : boolean

The type MyType is coming out as 'string', which is the expected behavior.

However, when I modify the code like this:

...

type MyType = typeof myObject.foo extends [infer First, ...infer Tail] ? string : boolean

Now, unexpectedly, MyType turns into 'boolean'. Why is that happening?

Why does it extend in the first case but not in the latter?

Answer №1

Scenario 1:

const myObject = {
  foo: ['a', 'b', 'c']
}

type MyType1 = string[] extends [...infer Content] ? string : boolean

[...infer Content] indicates that the tuple may have any number of elements. It has no restrictions.

Therefore, since string[] is an array without a specified length (not a tuple), you will get string.

Scenario 2


type MyType2 = string[] extends [infer First, ...infer Tail] ? string : boolean

[infer First, ...infer Tail] specifies that your tuple must have at least one element because of First. Since you are checking myObject.foo which is essentially string[], TypeScript cannot make any assumptions about the length of string[]. string[] is a mutable array.

Consider making myObject immutable.

const myObject = {
  foo: ['a', 'b', 'c']
} as const;

// string
type MyType1 = typeof myObject.foo extends readonly [...infer Content] ? string : boolean
// string
type MyType2 = typeof myObject.foo extends readonly [infer First, ...infer Tail] ? string : boolean

Playground

Now, both MyType's are strings.

CONCLUSION

['a', 'b', 'c'] is inferred as string[] because, as mentioned, it is an array and not a tuple.

If you want to treat it as a tuple, you can use ['a', 'b', 'c'] as const.

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

Sending various kinds of generic types to React component properties

Currently, my team and I are working on a TypeScript/React project that involves creating a versatile 'Wizard' component for multi-step processes. This Wizard acts as a container, receiving an array of 'panel' component properties and p ...

How can I extract a value from an object that is readonly, using a formatted string as the key?

I encountered a situation where I have code resembling the following snippet. It involves an object called errorMessages and multiple fields. Each field corresponds to various error messages in the errorMessages object, but using a formatted string to retr ...

Troubleshooting PHP's JSON array encoding issue

My current issue is with a PHP file that should be returning multiple records. Initially, everything was functioning properly. However, due to what I suspect is a minor error somewhere in the code, it has stopped working. When using Json_encode on my PHP ...

Uploading Files with Typescript Promises

Hello everyone, I'm facing an issue where a dialog window is opening before all the files are uploaded to the server. Can anyone please guide me on what might be going wrong in my code? public UploadAll() { this.doAsyncTask().then(() => ...

I am interested in creating a class that will produce functions as its instances

Looking to create a TypeScript class with instances that act as functions? More specifically, each function in the class should return an HTMLelement. Here's an example of what I'm aiming for: function generateDiv() { const div = document.crea ...

Is there a user-friendly interface in Typescript for basic dictionaries?

I'm not inquiring about the implementation of a dictionary in Typescript; rather, I'm curious: "Does Typescript provide predefined interfaces for common dictionary scenarios?" For instance: In my project, I require a dictionary with elements of ...

Why isn't my component calling the service.ts file?

In my Angular project, I am working on a home component that contains a specific method. This method is defined in a service file called service.ts and imported into the homecomponent.ts file. The method is named filterClicked with a condition within the s ...

Is there a way to create a universal getter/setter for TypeScript classes?

One feature I understand is setting getters and setters for individual properties. export class Person { private _name: string; set name(value) { this._name = value; } get name() { return this._name; } } Is there a w ...

Angular modules are designed to repeat chunks of code in a

Whenever I scroll the page, my function pushes items to an array. However, I am facing an issue where the pushed items are repeating instead of adding new ones. Solution Attempt onScroll(): void { console.log('scrolled'); var i,j,newA ...

Issue with Socket.io: Data not received by the last user who connected

I have developed a Node.js and Express application with real-time drawing functionality on canvas using socket.io version 1.7.2. Users are divided into separate socket rooms to enable multiple teams to draw independently. However, there is an issue where t ...

You are not able to use *ngIf nested within *ngFor in Angular 2

I am currently working in Angular2 and trying to bind data from a service. The issue I am facing is that when loading the data, I need to filter it by an ID. Here is what I am trying to achieve: <md-radio-button *ngFor="#item of items_list" ...

The assertion error `args[3]` must be an integer value, but it failed to meet the requirement

Software Version: v12.19.0 Operating System Platform: Linux ayungavis 5.4.0-48-generic #52~18.04.1-Ubuntu SMP Thu Sep 10 12:50:22 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux Subsystem: Steps to Reproduce the Issue I attempted to follow the tutorial provided ...

Assign a dynamic class to an element within an ngFor iteration

I am working with a template that includes an app-subscriber component being iterated over using *ngFor: <app-subscriber *ngFor="let stream of streams" [stream]="stream" [session]="session" (speakEvents)='onSpeakEvent($event)'> ...

Error encountered when utilizing a mixin in TypeScript due to a parameter issue

Recently, I delved into learning Typescript and decided to experiment with the mixin concept. The code snippet below may seem trivial, but it's all part of the learning process. Surprisingly, everything runs smoothly except for line 42, myInput.sendKe ...

Error message from OpenAI GPT-3 API: "openai.completions function not found"

I encountered an issue while trying to execute the test code from a tutorial on building a chat app with GPT-3, ReactJS, and Next.js. The error message I received was: TypeError: openai.completions is not a function This occurred when running the follow ...

Discover the highest value within an array of objects, along with any numerical object attributes that have a value greater than zero

Considering an array of objects structured as follows: [{ "202201": { "WO": 900, "WS": 0, "SY": 0.915, "LY": 0.98, "CT": 75 }, "202202" ...

Access file using operating system's pre-installed application

How can I open a file using the default application for that file type on different operating systems? For example, when opening an image.png on Mac, it should open with Preview, and on Windows with Windows Photo Viewer. I know you can use open image.png ...

Utilizing Sequelize's Where clause with the flexibility of optional parameters

Can you guide me on writing Sequelize queries with optional parameters? Consider the below query example: const result : SomeModel[] = await SomeModel.findAll( {where: { id: givenId, ...

Vue cannot detect the component that is provided by my plugin

This unique plugin, currently only includes a single component (coded in TypeScript): import _Vue, { PluginObject } from "Vue"; import MyComponent from "./MyComponent.vue"; const VuePlugin: PluginObject<void> = { install(Vue: typeof _Vue): void { ...

Issue: Unable to locate a differ that supports the object '[object Object]' of type 'object'. NgFor is only compatible with binding to Iterables like Arrays. Solution needed to resolve this

Code snippet for a service that returns JSON data export class EmployeeServiceService { constructor(private _http:Http) { } GetEmployees(): Observable<IEmployee[]>{ debugger; return this._http.get("http://localhost:2724/a ...