How does Typescript's dynamic tuple typing tool display all available options in Autocompletion/Intellisense?

Being new to TypeScript, I am facing an issue that I am unsure how to resolve.

I want to generate a list of tuples from a list of components. Each tuple should consist of the component's name (keyof MyComponents) and its attributes.

(Refer to the code below)

playground link

 interface MyComponents {
    Container: {
      fluid?: boolean
      className?: string
    },
    Tag: {
      text?: string
      className?: string
      hidden: boolean
    }
}

//Get the keys of the list of my components
type Element = keyof MyComponents

//Get the attributes depending on the element name
type PickAttributes<T extends Element> = Pick<MyComponents[T], keyof MyComponents[T]>

//Create a mapped tuple type [Element, Attributes]
// and the attributes depend on the element
export type Tuple = {

  [Element in keyof MyComponents]: [Element, PickAttributes<Element>]

}[keyof MyComponents]



const attr: PickAttributes<'Tag'> = {hidden: false} //This works and the auto completion works perfectly

const tuple1: Tuple = ["Tag", { hidden: false}] //This also works

const tuple2: Tuple = ["Container", { hidden: false}] //Error but it's normal as the element 'Container' doesn't have the property hidden:boolean

Everything is functioning correctly, however, there is an issue with autocompletion. When I enter the first element (Container, Tag, ...), the autocomplete for the second element (its attributes) displays all possible attributes, even incorrect ones.

For example, if I enter 'Tag' as the first element, it suggests 'fluid', but 'fluid' is only available in 'Container'! Intellisense shows all options

Furthermore, when I choose 'fluid', it recognizes that it is incompatible...

Typescript knows it's incompatible

Therefore, my question is: How can I limit autocomplete to show only valid attributes based on the element's name?

Any assistance would be greatly appreciated! Thank you!

Answer №1

When it comes to TypeScript, the type of the second element in a tuple cannot be determined solely based on the first element. TypeScript requires both elements to be declared in order to compare and ensure they match. This means that even if you specify the type for the first element, such as "Tag," TypeScript still needs the second element's type to validate the match. As a result, useful intellisense/autocomplete may not be readily available.

To address this issue, using generics is recommended. There are two main approaches:

#1 Transform your Tuple type into a generic structure:

export type Tuple<T extends keyof MyComponents> = [T, MyComponents[T]]

This approach constrains the type of T, allowing TypeScript to infer the tuple structure based on T. While explicit passing of T is required, it provides improved autocomplete capabilities.

#2 (preferable) Utilize generic functions:

Generic functions offer a more streamlined solution by inferring types without explicit definitions:

function makeTuple<T extends keyof MyComponents>(key: T, props: MyComponents[T]) {
  return [key, props];
}

const test1 = makeTuple("Tag", { hidden: true });
const test2 = makeTuple("Container", { fluid: true });

This method combines generic type arguments with function arguments, enabling enhanced autocomplete features without redundancy in code writing. It simplifies tuple initialization while maintaining effectiveness.

Playground

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

Deduce the argument type of a class from the super call

I'm currently working on a project utilizing the discord.js library. Within this project, there is an interface called ClientEvents which contains different event argument tuple types: interface ClientEvents { ready: []; warn: [reason: string] m ...

Troubleshooting issue of incorporating hintText in a TextField within a create-react-app-with-typescript

After recently downloading, installing, and running the create-react-app-with-typescript, I have been exploring different components. My latest experiment involved adding a TextField with hintText using the following code: import TextField from 'mate ...

Utilizing Angular to parse a JSON string generated with json.dumps

I am having trouble finding a solution that works for me. Currently, I am using python 3.6 (Django Rest Framework) on the server side and Angular 5 on the client side. This is the code on the server: class TypesView(APIView): def get(self,request): ...

Transforming a non-specific type into a container permits precarious assignments

I'm encountering an issue with the code snippet provided below. Despite having a specific type where Type<boolean> cannot be assigned to Type<true>, when wrapping it in an object type (BoxType as shown), suddenly BoxType<boolean> wro ...

What are some alternatives for integrating React production build files apart from utilizing Express?

Is there a way to integrate React into my library using the HTTP module? I'm trying to figure out how to recursively send static files. Specifically, I want to include the build folder from the React production build, but I'm not sure how to go a ...

Issues arise when using Android BluetoothLeAdvertiser in Nativescript applications

I've been working on creating a Nativescript application that can send Bluetooth low energy advertisements. Since there are no existing Nativescript plugins for this functionality, I decided to develop a Java library (with plans to add a Swift library ...

How do I define two mutations in a single component using TypeScript and react-apollo?

After exploring this GitHub issue, I have successfully implemented one mutation with Typescript. However, I have been unable to figure out how to use 2 mutations within the same component. Currently, there is only a single mutate() function available in t ...

Inserting items into an array entity

I am attempting to insert objects into an existing array only if a certain condition is met. Let me share the code snippet with you: RequestObj = [{ "parent1": { "ob1": value, "ob2": { "key1": value, "key2": va ...

Having difficulty resolving all parameters for the component: (?, [object Object]) in the Jasmine component Unit Test

While defining a UT for a component with an extended class using i8nService and ChangeDetectionRef, I encountered an error preventing me from instantiating it: Failed: Can't resolve all parameters for BrandingMultiselectComponent: (?, [object Object] ...

Ways to resolve the issue: ""@angular/fire"' does not contain the exported member 'AngularFireModule'.ts(2305) in an ionic, firebase, and

I am facing an issue while attempting to establish a connection between my app and a firebase database. The problem arises as I receive 4 error messages in the app.module.ts file: '"@angular/fire"' has no exported member 'AngularFi ...

How to add an item to an array in JavaScript without specifying a key

Is there a way to push an object into a JavaScript array without adding extra keys like 0, 1, 2, etc.? Currently, when I push my object into the array, it automatically adds these numeric keys. Below is the code snippet that I have tried: let newArr = []; ...

Issue occurred while trying to render a React component with Typescript and WebPack

I am in the process of creating a basic React component that simply displays a page saying Hello. However, I'm encountering an error in my console. My compiler of choice is TypeScript. To set up my project, I am following this guide: https://github.co ...

What is the best way to create an interface that only allows keys to be a combination of values from a specific property found within each object of an array?

interface Filter { id: string; name: string; } type Filters = Filter[]; const filters = [{ id: 'f1', name: 'f1name'}, { id: 'f2', name: 'f2name'}] interface State { ... } const state = { f1: any, ...

Having completed "npm link" and "npm i <repo>", the module cannot be resolved despite the presence of "main" and "types" in the package.json file

Here is the contents of my package.json file: { "name": "ts-logger", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "install": "tsc" ...

Guide on navigating an array of objects using the provided keys as a starting point in Javascript/Typescript

Assuming I have an array of objects structured like this: const events: Array<{year: number, month: number, date: number}> = [ {year: 2020, month: 10, date: 13}, {year: 2021: month: 3, date: 12}, {year: 2021: month: 9, date: 6}, {year: 2021: mont ...

Resolving the error "Property not found on type 'any[]' after retrieving an object from the database in Typescript"

Being a beginner in the world of TypeScript, I am struggling to comprehend the error message and how to resolve it. This is the snippet of my code: app.put('/compareSpread' , async (req , res) => { const { roundedSpreadPercentage , cropId} ...

What is the reason for TypeScript not throwing an error when an interface is not implemented correctly?

In my current scenario, I have a class that implements an interface. Surprisingly, the TypeScript compiler does not throw an error if the class fails to include the required method specified by the interface; instead, it executes with an error. Is there a ...

Issues arise when trying to type ChangeEvent in React using Typescript

After spending some time learning React with TypeScript, I encountered a problem. The prop onChangeHandler in my code takes a function to modify properties in formik values. <Formik<FormModel> initialValues={{ favorite: ...

Angular Error: Unable to access property 'users' on a null value

I am working on a component that takes in data through the @Input() decorator regarding a group. My objective is to generate a new array of objects during the initialization of the component based on the data from the group array. Below is the TypeScript c ...

It is not necessary to specify a generic type on a Typescript class

When working with Typescript and default compiler options, there are strict rules in place regarding null values and uninitialized class attributes in constructors. However, with generics, it is possible to define a generic type for a class and create a ne ...