Pass generics to JSX elements in TypeScript (2023)

TypeScript 2.9 added the ability to specify type arguments for generic JSX elements. This means that we can now write the following component in a TSX file:

occupation The image() { // ... give back(<select<string> options={targets} bravura={target} after the change={define goal}/>);}

To understand why generic JSX elements are useful (and why we usually don't need to write the type argument explicitly), let's create the aboveselectcomponent and iterate over its static types. Here we go!

#Step #1: Implementselectin JavaScript/JSX

Let's go ahead and implement a reusableselectreacting component. Our component needs to render natively<select>item with a lot<Option>Kinder:

Pass generics to JSX elements in TypeScript (1)

we want this to happenoptionsas an accessory toselectcomponent and the currently selectedbravurait is aafter the changeCall back. Here is the code for the component shown in the screenshot above:

occupation The image() { Constantly Goals =[{Bravura: "es3", Hashtag: "ECMAScript 3"},{Bravura: "es5", Hashtag: "ECMAScript 5"},{Bravura: "es2015", Hashtag: "ECMAScript 2015"},{Bravura: "yo2016", Hashtag: "ECMAScript 2016"},{Bravura: "es2017", Hashtag: "ECMAScript 2017"},{Bravura: "es2018", Hashtag: "ECMAScript 2018"},{Bravura: "es2019", Hashtag: "ECMAScript 2019"},]; Constantly[Meta,set a goal]= useState("es2019"); give back(<select options={targets} bravura={target} after the change={define goal}/>);}

How could we implement thisselectComponent in plain JavaScript and JSX? Here's a first try:

occupation select(Accessories) { occupation handleOnChange(e) { accessories.after the change(mi.current target.bravura);} give back(<select bravura={accessories.bravura}after the change={controlarcâmbio}>{accessories.options.Map(Possibility=>(<possibility key={possibility.bravura}bravura={possibility.bravura}>{possibility.Hashtag}</possibility>))}</select>);}

Our component accepts props and returns a<select>element containing all options specified byoptionsSupport, support. We also define a functionhandleOnChangewhich is called every time the selected value changes; turn onafter the changeCallback with the selected value.

This component works as expected! Now let's write statically in TypeScript and TSX.

(Video) No BS TS #7 - Generics in Typescript

#Step #2: Implementselectde TypeScript/TSX

We'll start by creating a type that models a single option. let's call itpossibilityand define two properties, one for the underlying value and one for the label we want to display:

he writes possibility ={bravura: line;Hashtag: line;};

That was easy enough. Next, let's specify a type for the accessory.selectComponent. we need oneoptionssupport using thosepossibilitytype we just created, abravuraprop to the currently selected value and aafter the changeCallback to be called each time the selected value changes:

he writes accessories ={options: possibility[];bravura: line; after the change:(Bravura: line)=> Archive;};

Finally we will dieaccessoriesand add a type annotation to the parametermiourhandleOnChangeOccupation:

occupation select(Accessories: accessories) { occupation handleOnChange(mi: To react.form event<HTMLSelectElement>) { accessories.after the change(mi.current target.bravura);} give back(<select bravura={accessories.bravura}after the change={controlarcâmbio}>{accessories.options.Map(Possibility=>(<possibility key={possibility.bravura}bravura={possibility.bravura}>{possibility.Hashtag}</possibility>))}</select>);}

We now have a fully statically typed React component. Currently all options must specify a value of typeline, a constraint that can be too restrictive in a real-world application. (Or it might not be! In that case, we can stop there.)

#Step 3: Supported Numeric Option Values

While using string values ​​is a common usage, it's certainly not the only one! we can want thoseselectComponent to also accept numerical option values:

occupation The image() { Constantly Goals =[{Bravura: 3, Hashtag: "ECMAScript 3"},{Bravura: 5, Hashtag: "ECMAScript 5"},{Bravura: 2015, Hashtag: "ECMAScript 2015"},{Bravura: 2016, Hashtag: "ECMAScript 2016"},{Bravura: 2017, Hashtag: "ECMAScript 2017"},{Bravura: 2018, Hashtag: "ECMAScript 2018"},{Bravura: 2019, Hashtag: "ECMAScript 2019"},]; Constantly[Meta,set a goal]= useState(2019); give back(<select options={targets} bravura={target} after the change={define goal}/>);}

Note that I replaced the string values ​​with numerical values, including the initial value passed to theuseStatehook.

Before updating the types to ourselectcomponent, we've added support for non-string option values ​​to ourhandleOnChangeOccupation. Currently it only works correctly when working with string values.e.Target.Actualis always a string, even if we specify numerical values ​​for our options.

(Video) Typescript Generics Tutorial

Fortunately, the solution is pretty short. instead of readinge.Target.Actualand deliver itafter the changeCallback directly, we can get the index of the selected option through thee.current target.selected indexProperty. So we can choose ouroptionsArray at that index and callafter the changewith its value:

occupation select(Accessories: accessories) { occupation handleOnChange(mi: To react.form event<HTMLSelectElement>) { Constantly{index selected}= mi.current target; Constantly selected option = accessories.options[selected index]; accessories.after the change(selected option.bravura);} give back(<select bravura={accessories.bravura}after the change={controlarcâmbio}>{accessories.options.Map(Possibility=>(<possibility key={possibility.bravura}bravura={possibility.bravura}>{possibility.Hashtag}</possibility>))}</select>);}

This approach works because we represent a person<Option>element for each element notoptionsArray, keeps its order and doesn't add more<Option>Elements.

Now that we have determined the implementation of ourselectcomponent, let's fix their types. We are currently getting some kind of error because we are makingMeta(which is inferred as typenumber) While thebravuraprop (which must be of typeline).

Let's change the nature ofbravuraProperty oflineonestring | numberto also support numeric values:

he writes option value = line | number;he writes possibility ={bravura: option value;Hashtag: line;};he writes accessories ={options: possibility[];bravura: option value; after the change:(Bravura: option value)=> Archive;};

Notice that I introduced a type alias calledoption valueso we don't need to repeat the union typestring | numberat several points.

unfortunately ouraccessoriesthe type is not right. Our option values ​​are now written asstring | number, but it also means that ourafter the changeCallback receives a value of typestring | number. This type does not model the behavior of theselectcorrect component:

  • If we pass option values ​​of typeline, to dieafter the changeCallback receives a value of typeline.
  • If we pass option values ​​of typenumber, to dieafter the changeCallback receives a value of typenumber.

In other words, we lose type information along the way. This is problematic when we want to use the parameter, for example if we want to callset a goalfunction returned by ouruseStateHook:

(Video) React TypeScript Tutorial - 19 - Generic Props

  • when we calluseStatewith an initial value of"es2019", which is a string, infers TypeScriptMetabe friendlyline.
  • when we calluseStatewith an initial value of2019, which is a number that TypeScript infersMetabe friendlynumber.

In any case, a value of typestring | numberis not assignablelineI am notnumber. Therefore, TypeScript throws a type error for theafter the changesupport ourselectElement:

Number type cannot be assigned to SetStateAction type'.

So how do we properly write our React component? The answer isgeneric.

#Step 4 - Using Generics for Precise Accessory Types

Instead of using the typestring | numberLet's use a generic type everywhereTby the values ​​of our options. let's do ouroptionsWrite generically by adding a list of type parameters. Then we use the typeTFor himbravuraProperty:

he writes option value = line | number;he writes possibility<T expanded option value>={bravura: T;Hashtag: line;};

Note that we restrict the type parameterTto expand ouroption valuehe writes. In other words, we can specify any type for the generic type.Tto which it will be assignedstring | number. This one contains…

  • To dielinehe writes,
  • To dienumberhe writes,
  • NoneString-Literaltyp,
  • Nonenumeric literal type,
  • To dienever write, j
  • any combination of the above.

Now that thepossibilitytype is generic, we must provide a type argument when using it tooptionssupport in ouraccessorieshe writes. This, in turn, means that we must actaccessoriesalso generic. Again, let's introduce a generic type parameterTand use it forbravurajafter the changeAccessories:

he writes accessories<T expanded option value>={options: possibility<T>[];bravura: T; after the change:(Bravura: T)=> Archive;};

now thisaccessoriesis a generic type, we need to provide a type argument for the type parameterTif you useaccessoriesinside ourselectComponent. We have to repeat that tooExpand option valueRestriction so we can passToneAccessories<T>- they are turtles down:

(Video) React Components with GENERICS? - Advanced TypeScript

occupation select<T expanded option value> (accessories: accessories<T>) { occupation handleOnChange(mi: To react.form event<HTMLSelectElement>) { Constantly{index selected}= mi.current target; Constantly selected option = accessories.options[selected index]; accessories.after the change(selected option.bravura);} give back(<select bravura={accessories.bravura}after the change={controlarcâmbio}>{accessories.options.Map(Possibility=>(<possibility key={possibility.bravura}bravura={possibility.bravura}>{possibility.Hashtag}</possibility>))}</select>);}

we are successfulselecta generic functional component. in itself. This is where TypeScript 2.9 comes in! We can specify a generic type when creating<Select>JSX Element:

occupation The image() { Constantly Goals =[{Bravura: "es3", Hashtag: "ECMAScript 3"},{Bravura: "es5", Hashtag: "ECMAScript 5"},{Bravura: "es2015", Hashtag: "ECMAScript 2015"},{Bravura: "yo2016", Hashtag: "ECMAScript 2016"},{Bravura: "es2017", Hashtag: "ECMAScript 2017"},{Bravura: "es2018", Hashtag: "ECMAScript 2018"},{Bravura: "es2019", Hashtag: "ECMAScript 2019"},]; Constantly[Meta,set a goal]= useState("es2019"); give back(<select<string> options={targets} bravura={target} after the change={define goal}/>);}

Of course, the syntax looks a little strange at first. However, upon reflection, it's consistent with how we've specified generic arguments elsewhere in TypeScript.

Now that we've done itselectcomponent and bothaccessoriesjpossibilitygeneric types, our program type checks seamlessly: no more type errors whether we use strings, numbers, or both for our option values.

Note that we don't need to explicitly specify the generic type argument in the JSX element here. TypeScript can infer this for us! Looking at the type ofbravuraProperties of objects in ourGoalsarray, TypeScript understands that we use values ​​of typelinein this example.

Because TypeScript can infer type contextuallylinefor we can change<Select<Sequence>single again<Select. Here is the complete working example:

he writes option value = line | number;he writes possibility<T expanded option value>={bravura: T;Hashtag: line;};he writes accessories<T expanded option value>={options: possibility<T>[];bravura: T; after the change:(Bravura: T)=> Archive;};occupation select<T expanded option value> (accessories: accessories<T>) { occupation handleOnChange(mi: To react.form event<HTMLSelectElement>) { Constantly{index selected}= mi.current target; Constantly selected option = accessories.options[selected index]; accessories.after the change(selected option.bravura);} give back(<select bravura={accessories.bravura}after the change={controlarcâmbio}>{accessories.options.Map(Possibility=>(<possibility key={possibility.bravura}bravura={possibility.bravura}>{possibility.Hashtag}</possibility>))}</select>);}occupation The image() { Constantly Goals =[{Bravura: "es3", Hashtag: "ECMAScript 3"},{Bravura: "es5", Hashtag: "ECMAScript 5"},{Bravura: "es2015", Hashtag: "ECMAScript 2015"},{Bravura: "yo2016", Hashtag: "ECMAScript 2016"},{Bravura: "es2017", Hashtag: "ECMAScript 2017"},{Bravura: "es2018", Hashtag: "ECMAScript 2018"},{Bravura: "es2019", Hashtag: "ECMAScript 2019"},]; Constantly[Meta,set a goal]= useState("es2019"); give back(<select options={targets} bravura={target} after the change={define goal}/>);}

And let's go! a static typeselectComponent in React using generic type arguments for JSX elements.

This article and 44 others are part of theTypescript-EvolutionLine. Take a look!

(Video) TypeScript Tutorial #18 - Generics

FAQs

How do you pass a generic type in TypeScript? ›

Assigning Generic Parameters

By passing in the type with the <number> code, you are explicitly letting TypeScript know that you want the generic type parameter T of the identity function to be of type number . This will enforce the number type as the argument and the return value.

Can you use TypeScript with JSX? ›

TypeScript supports embedding, type checking, and compiling JSX directly to JavaScript.

Should I use TSX or JSX? ›

So if you're not sure, here's how to decide which extension to use: File that include a React component using JSX syntax use . tsx. All other files (eg, utility functions, classes, redux reducers, etc) use .

Can we use generics in TypeScript? ›

TypeScript also supports generic classes. The generic type parameter is specified in angle brackets (<>) following the name of the class. A generic class can have generic fields or methods.

How do generics work in TypeScript? ›

Generics allow creating 'type variables' which can be used to create classes, functions & type aliases that don't need to explicitly define the types that they use. Generics makes it easier to write reusable code.

Is it possible to inherit from a generic type? ›

An attribute cannot inherit from a generic class, nor can a generic class inherit from an attribute.

What is TypeScript generics for React component? ›

TypeScript Generics is a tool that provides a way to create reusable components. It creates a component that can work with a variety of data types rather than a single data type. It allows users to consume these components and use their own types.

How do you pass properties from one component to another in React? ›

For passing the data from the child component to the parent component, we have to create a callback function in the parent component and then pass the callback function to the child component as a prop. This callback function will retrieve the data from the child component.

What is JSX element in TypeScript? ›

JSX is majorly used with React framework and now TypeScript also supports the compilation of JSX into JavaScript. For using JSX, there are two most important things which should be done: . tsx should be the file extension of the files used.

Is TypeScript better than JSX? ›

Thanks to static typing and declaration files TypeScript code is much easier to maintain and share. Also, TypeScript works great in bug prevention and helps to avoid spending time looking through code to find a silly mistake. So, it is better to use TypeScript for large projects.

Is it good practice to use TypeScript in React? ›

Using TypeScript with React provides several advantages in application-building, including the option of simpler React components and better JavaScript XML (JSX) support for static type validation.

Why is JSX faster than JavaScript? ›

JSX performs optimization while compiling the source code to JavaScript. The generated code runs faster than an equivalent code written directly in JavaScript. The gain may vary, but even the optimized JavaScript libraries like Box2D becomes faster when ported to JSX (12% faster on iOS 5.1, 29% faster on Android 2.3).

Does JSX need Babel? ›

If you work on a React project, chances are you have to deal with Babel. It is needed for 2 main tasks: To compile JSX into React. createElement API calls.

Why use TSX over JSX? ›

The . ts file extension is used when you are creating functions, classes, reducers, etc. that do not require the use of JSX syntax and elements, whereas the . tsx file extension is used when you create a React component and use JSX elements and syntax.

Can you pass a type as a parameter TypeScript? ›

Yes, you can use a generic type parameter and then either pass a type argument or allow TypeScript to infer it (if it can).

How do you declare a generic class in TypeScript? ›

To define generic classes in TypeScript, we put the generic type marker in between the <> after the class name. We can have more than one type marker separated by a comma. Also, we can use the same type marker to mark the type of the function to let us change parameter and return type of methods within our class.

Is it bad practice to use any in TypeScript? ›

Don't use any as a type unless you are in the process of migrating a JavaScript project to TypeScript. The compiler effectively treats any as “please turn off type checking for this thing”. It is similar to putting an @ts-ignore comment around every usage of the variable.

What is == and === in TypeScript? ›

Strict equality using === Loose equality using == Same-value equality using Object.is() Same-value-zero equality.

What is '!' In TypeScript? ›

What is the TypeScript exclamation mark? The non-null assertion operator tells the TypeScript compiler that a value typed as optional cannot be null or undefined . For example, if we define a variable as possibly a string or undefined, the ! operator tells the compiler to ignore the possibility of it being undefined.

Does TypeScript support generic interface? ›

In TypeScript, you can create generic functions, generic methods, generic interfaces, and generic classes.

What are the four 4 classification types of inheritance? ›

Explore 5 Types of Inheritance in C++ With Examples
  • Single Inheritance.
  • Multiple Inheritance.
  • Multilevel Inheritance.
  • Hierarchical Inheritance.
  • Hybrid Inheritance.
Nov 22, 2022

How do you inherit a generic class? ›

You cannot inherit a generic type.
...
To answer your specific question, the order of things in a class declaration is:
  1. attributes, in square brackets.
  2. modifiers ("public", "static", and so on)
  3. "partial"
  4. "class"
  5. the class name.
  6. a comma-separated list of type parameter declarations inside angle brackets.
Jan 5, 2010

What Cannot be inherited from parent class? ›

Following are the properties which a derived class doesn't inherit from its parent class : 1) The base class's constructors and destructor. 2) The base class's friend functions. 3) Overloaded operators of the base class.

Can you use generics with interfaces? ›

Java Generics Bounded Type Parameters

Bounded type parameters can be used with methods as well as classes and interfaces.

Why do we use generics instead of object? ›

Generics is flexible and safe. At the same time, working with Object that requires type-casting is error-prone.

Can we use functional component in TypeScript? ›

Functional Components usually take a props parameter and return a JSX element or null . When we need to use TypeScript to define a Functional Component, we have 4 ways, each of which has its own advantages and disadvantages, depending on the specific situation.

How to pass state from one component to another functional component? ›

To do this, we can use the update function of the state that we get in useState, passing it as props to the components that need it.
...
You just have to:
  1. Lift your state up.
  2. Pass down the contents of your state and the function that updates it.
  3. Trigger your state to update with a user interaction (clicking on a button).
Aug 11, 2022

How to pass data one component to another component in Angular? ›

Methods to Share Data Between Angular Components
  1. Goals. Data Sharing Between Angular Components. ...
  2. Specifications. ...
  3. Method1: Parent to Child via @Input. ...
  4. Method 2: Child to Parent via @Output and EventEmitter. ...
  5. Method3: Child to Parent via @ViewChild. ...
  6. Method 4: Unrelated Components via a Service.
Jul 22, 2022

How do you pass a state from one component to another class component? ›

Passing State to a Component

To pass the state into another component, you can pass it as a prop. Then, inside <ExampleComponent /> , you can access the data as this. props.

How do I pass JSX in props? ›

You want to use JSX inside your props

You can simply use {} to cause JSX to parse the parameter. The only limitation is the same as for every JSX element: It must return only one root element.

Can we store a JSX element in a variable? ›

Using JSX, you can create a function and return a set of JSX elements to a variable, and that variable used is to render the elements inside the render() function in React.

Can we pass JSX as props? ›

Not only can JSX elements be passed as props to components, but we can also pass other components as props.

Is TypeScript still popular? ›

Typescript is essentially JavaScript that improves developer experience. It can be run on Node. js or any browser which supports ECMAScript 3 or newer versions. Recently typescript jumped 4.64% points from its 2021 standing to overtake Java as one of the most popular programming languages in the world.

Is TypeScript deprecated? ›

However, the Script Editor application is still part of macOS, and AppleScript is not deprecated. There are alternative solutions to scripting, like Automator and Shortcuts that Apple will probably prioritise and for application programming Swift or Obj-C is preferred over a scripting language in most cases.

What cant be used in JSX? ›

reactjs - Component cannot be used as a JSX component.

What is disadvantage of TypeScript? ›

Another disadvantage of TypeScript is the required extra compilation step. This step can slow down the build time and complicate the bundler setup. Since TypeScript adds many new features that can be unknown to a frontend developer, it increases the learning curve of a codebase.

Is TypeScript Overhyped? ›

TypeScript is a good language but a bit too much overhyped. You could still try to advocate for it in large codebases. It might have some advantages if your team has the knowledge. However, for small projects or MVP applications, I would advise against it.

Why not to use TypeScript in React? ›

It has a longer learning curve than JavaScript, so if you have a team of JavaScript developers and no TypeScript experts, there will be a learning curve that they need to climb before they hit 100% productivity. Side note: Coming from another language with advanced types to TypeScript can be really fast.

Is JSX out of business? ›

JSX continues to operate from the airport.

Who is JSX competitor? ›

The closest competitor to the jsx.com is flyxo.com that ranks 315482 worldwide, 109690 in United States.

Which framework is faster than React? ›

Svelte is a newer framework with a shallower learning curve. It offers cleaner code and a faster development process. It is also easier to debug than React. And it can be used to develop a web app without extensive knowledge of HTML.

Do we still need Babel in 2022? ›

Conclusion. Having Babel and TypeScript do part of the source transform seems unnecessarily complicated. So, if you are using both, it is better to use Babel for transpiling and the TypeScript compiler for type checking.

What is the difference between Babel and JSX? ›

Babel is a transpiler that turns input code into "pure" JavaScript. JSX is a syntax sugar over JavaScript.

Can we write JSX without React? ›

JSX is not a requirement for using React. Using React without JSX is especially convenient when you don't want to set up compilation in your build environment. Each JSX element is just syntactic sugar for calling React. createElement(component, props, ...children) .

Can we use JSX in TypeScript? ›

In order to use JSX you must do two things. TypeScript ships with three JSX modes: preserve , react , and react-native . These modes only affect the emit stage - type checking is unaffected. The preserve mode will keep the JSX as part of the output to be further consumed by another transform step (e.g. Babel).

Should hooks be TS or TSX? ›

You can use hooks in . ts files. . tsx is if you need to use JSX expressions.

Can I convert JSX to TSX? ›

You could use the react-javascript-to-typescript-transform package to automatically convert/port React JSX to Typescript TSX. Code can be transformed via the CLI e.g. react-js-to-ts reactFile. js The following example is taken from the projects website. A standard react component e.g.

How do you pass an object as a parameter in TypeScript? ›

Inside the function we assign the parameters to properties in the object. To do this, we have to specify the this keyword, which refers to the calling object. The variables and parameters may have the same names. Anything we pass to the constructor as an argument, will be assigned to the property of the object.

How do you pass a value to a function in TypeScript? ›

Parameters are a mechanism to pass values to functions. Parameters form a part of the function's signature. The parameter values are passed to the function during its invocation. Unless explicitly specified, the number of values passed to a function must match the number of parameters defined.

What does @param do in TypeScript? ›

Params enable methods to receive a variable number of parameters. Basically, if you are using params (... variable name) in TypeScript, the argument passed to the method are changed by the compiler into an element in a temporary array and this array is then used in the receiving methods.

What is the difference between argument and parameter in TypeScript? ›

Note the difference between parameters and arguments: Function parameters are the names listed in the function's definition. Function arguments are the real values passed to the function.

What are the two different types of parameter passing? ›

A Parameter is the symbolic name for "data" that goes into a function. There are two ways to pass parameters in C: Pass by Value, Pass by Reference.

Does TypeScript pass by reference or value? ›

Primitive data types like string, number, boolean, undefined and the null object is passed in by value in TypeScript.

What are the five methods of parameter passing? ›

6.1. Parameter-Passing Mechanisms
  • Call-by-value.
  • Call-by-reference.
  • Call-by-copy-restore (also known as value-result, copy-in-copy-out)

How can we pass an object as a parameter to a method? ›

To pass an object as an argument we write the object name as the argument while calling the function the same way we do it for other variables. Syntax: function_name(object_name); Example: In this Example there is a class which has an integer variable 'a' and a function 'add' which takes an object as argument.

How do you pass data through a function? ›

When there are multiple functions (which is most of the time), there needs to be a way to pass data between the functions. This is done by passing values in parenthesis: myFunction(myData). Even when there is no data to be passed, we still have to declare and execute functions by using parenthesis: myFunction().

Can we pass variables to functions? ›

Parameters to functions are references to objects, which are passed by value. When you pass a variable to a function, python passes the reference to the object to which the variable refers (the value). Not the variable itself. Functions have a local variable table called a local namespace.

Videos

1. Generics in Typescript | Typescript Generic Function - Easy Explained
(Monsterlessons Academy)
2. 10 Tips for Mastering TypeScript Generics
(Matt Pocock)
3. Advanced TypeScript: Let’s Learn Generics!
(Learn With Jason)
4. WHEN should I use a Generic? - Advanced TypeScript
(Matt Pocock)
5. Typescript Generics | Beginners Tutorial with Examples
(Dave Gray)
6. 22 TypeScript Course - generics in typescript
(Bitfumes)

References

Top Articles
Latest Posts
Article information

Author: Kerri Lueilwitz

Last Updated: 23/09/2023

Views: 5724

Rating: 4.7 / 5 (47 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Kerri Lueilwitz

Birthday: 1992-10-31

Address: Suite 878 3699 Chantelle Roads, Colebury, NC 68599

Phone: +6111989609516

Job: Chief Farming Manager

Hobby: Mycology, Stone skipping, Dowsing, Whittling, Taxidermy, Sand art, Roller skating

Introduction: My name is Kerri Lueilwitz, I am a courageous, gentle, quaint, thankful, outstanding, brave, vast person who loves writing and wants to share my knowledge and understanding with you.