Documentation - Generics (2023)

A major part of software engineering is building components that not only have well-defined and consistent APIs, but are also reusable.Components that are capable of working on the data of today as well as the data of tomorrow will give you the most flexible capabilities for building up large software systems.

In languages like C# and Java, one of the main tools in the toolbox for creating reusable components is generics, that is, being able to create a component that can work over a variety of types rather than a single one.This allows users to consume these components and use their own types.

Hello World of Generics

To start off, let’s do the “hello world” of generics: the identity function.The identity function is a function that will return back whatever is passed in.You can think of this in a similar way to the echo command.

Without generics, we would either have to give the identity function a specific type:

ts

function identity(arg: number): number {

return arg;

}

Try

Or, we could describe the identity function using the any type:

ts

function identity(arg: any): any {

return arg;

}

Try

While using any is certainly generic in that it will cause the function to accept any and all types for the type of arg, we actually are losing the information about what that type was when the function returns.If we passed in a number, the only information we have is that any type could be returned.

Instead, we need a way of capturing the type of the argument in such a way that we can also use it to denote what is being returned.Here, we will use a type variable, a special kind of variable that works on types rather than values.

ts

function identity<Type>(arg: Type): Type {

return arg;

}

Try

We’ve now added a type variable Type to the identity function.This Type allows us to capture the type the user provides (e.g. number), so that we can use that information later.Here, we use Type again as the return type. On inspection, we can now see the same type is used for the argument and the return type.This allows us to traffic that type information in one side of the function and out the other.

We say that this version of the identity function is generic, as it works over a range of types.Unlike using any, it’s also just as precise (i.e., it doesn’t lose any information) as the first identity function that used numbers for the argument and return type.

Once we’ve written the generic identity function, we can call it in one of two ways.The first way is to pass all of the arguments, including the type argument, to the function:

ts

let output = identity<string>("myString");

let output: string

Try

Here we explicitly set Type to be string as one of the arguments to the function call, denoted using the <> around the arguments rather than ().

The second way is also perhaps the most common. Here we use type argument inference — that is, we want the compiler to set the value of Type for us automatically based on the type of the argument we pass in:

ts

let output = identity("myString");

let output: string

Try

Notice that we didn’t have to explicitly pass the type in the angle brackets (<>); the compiler just looked at the value "myString", and set Type to its type.While type argument inference can be a helpful tool to keep code shorter and more readable, you may need to explicitly pass in the type arguments as we did in the previous example when the compiler fails to infer the type, as may happen in more complex examples.

Working with Generic Type Variables

When you begin to use generics, you’ll notice that when you create generic functions like identity, the compiler will enforce that you use any generically typed parameters in the body of the function correctly.That is, that you actually treat these parameters as if they could be any and all types.

Let’s take our identity function from earlier:

ts

function identity<Type>(arg: Type): Type {

return arg;

(Video) Generic Swift: It Isn’t Supposed to Hurt - Rob Napier

}

Try

What if we want to also log the length of the argument arg to the console with each call?We might be tempted to write this:

ts

function loggingIdentity<Type>(arg: Type): Type {

console.log(arg.length);

Property 'length' does not exist on type 'Type'.2339Property 'length' does not exist on type 'Type'.

return arg;

}

Try

When we do, the compiler will give us an error that we’re using the .length member of arg, but nowhere have we said that arg has this member.Remember, we said earlier that these type variables stand in for any and all types, so someone using this function could have passed in a number instead, which does not have a .length member.

Let’s say that we’ve actually intended this function to work on arrays of Type rather than Type directly. Since we’re working with arrays, the .length member should be available.We can describe this just like we would create arrays of other types:

ts

function loggingIdentity<Type>(arg: Type[]): Type[] {

console.log(arg.length);

return arg;

}

Try

You can read the type of loggingIdentity as “the generic function loggingIdentity takes a type parameter Type, and an argument arg which is an array of Types, and returns an array of Types.”If we passed in an array of numbers, we’d get an array of numbers back out, as Type would bind to number.This allows us to use our generic type variable Type as part of the types we’re working with, rather than the whole type, giving us greater flexibility.

We can alternatively write the sample example this way:

ts

function loggingIdentity<Type>(arg: Array<Type>): Array<Type> {

console.log(arg.length); // Array has a .length, so no more error

return arg;

}

Try

You may already be familiar with this style of type from other languages.In the next section, we’ll cover how you can create your own generic types like Array<Type>.

Generic Types

In previous sections, we created generic identity functions that worked over a range of types.In this section, we’ll explore the type of the functions themselves and how to create generic interfaces.

The type of generic functions is just like those of non-generic functions, with the type parameters listed first, similarly to function declarations:

ts

function identity<Type>(arg: Type): Type {

return arg;

}

let myIdentity: <Type>(arg: Type) => Type = identity;

Try

We could also have used a different name for the generic type parameter in the type, so long as the number of type variables and how the type variables are used line up.

ts

function identity<Input>(arg: Input): Input {

return arg;

}

let myIdentity: <Input>(arg: Input) => Input = identity;

Try

We can also write the generic type as a call signature of an object literal type:

ts

function identity<Type>(arg: Type): Type {

return arg;

}

let myIdentity: { <Type>(arg: Type): Type } = identity;

Try
(Video) Swift Generics for Beginners - Eliminate Code Duplication

Which leads us to writing our first generic interface.Let’s take the object literal from the previous example and move it to an interface:

ts

interface GenericIdentityFn {

<Type>(arg: Type): Type;

}

function identity<Type>(arg: Type): Type {

return arg;

}

let myIdentity: GenericIdentityFn = identity;

Try

In a similar example, we may want to move the generic parameter to be a parameter of the whole interface.This lets us see what type(s) we’re generic over (e.g. Dictionary<string> rather than just Dictionary).This makes the type parameter visible to all the other members of the interface.

ts

interface GenericIdentityFn<Type> {

(arg: Type): Type;

}

function identity<Type>(arg: Type): Type {

return arg;

}

let myIdentity: GenericIdentityFn<number> = identity;

Try

Notice that our example has changed to be something slightly different.Instead of describing a generic function, we now have a non-generic function signature that is a part of a generic type.When we use GenericIdentityFn, we now will also need to specify the corresponding type argument (here: number), effectively locking in what the underlying call signature will use.Understanding when to put the type parameter directly on the call signature and when to put it on the interface itself will be helpful in describing what aspects of a type are generic.

In addition to generic interfaces, we can also create generic classes.Note that it is not possible to create generic enums and namespaces.

Generic Classes

A generic class has a similar shape to a generic interface.Generic classes have a generic type parameter list in angle brackets (<>) following the name of the class.

ts

class GenericNumber<NumType> {

zeroValue: NumType;

add: (x: NumType, y: NumType) => NumType;

}

let myGenericNumber = new GenericNumber<number>();

myGenericNumber.zeroValue = 0;

myGenericNumber.add = function (x, y) {

return x + y;

};

Try

This is a pretty literal use of the GenericNumber class, but you may have noticed that nothing is restricting it to only use the number type.We could have instead used string or even more complex objects.

ts

let stringNumeric = new GenericNumber<string>();

stringNumeric.zeroValue = "";

(Video) Ultimate Guide to C# Generics: Type-Safe and Reusable Code Explained

stringNumeric.add = function (x, y) {

return x + y;

};

console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

Try

Just as with interface, putting the type parameter on the class itself lets us make sure all of the properties of the class are working with the same type.

As we cover in our section on classes, a class has two sides to its type: the static side and the instance side.Generic classes are only generic over their instance side rather than their static side, so when working with classes, static members can not use the class’s type parameter.

Generic Constraints

If you remember from an earlier example, you may sometimes want to write a generic function that works on a set of types where you have some knowledge about what capabilities that set of types will have.In our loggingIdentity example, we wanted to be able to access the .length property of arg, but the compiler could not prove that every type had a .length property, so it warns us that we can’t make this assumption.

ts

function loggingIdentity<Type>(arg: Type): Type {

console.log(arg.length);

Property 'length' does not exist on type 'Type'.2339Property 'length' does not exist on type 'Type'.

return arg;

}

Try

Instead of working with any and all types, we’d like to constrain this function to work with any and all types that also have the .length property.As long as the type has this member, we’ll allow it, but it’s required to have at least this member.To do so, we must list our requirement as a constraint on what Type can be.

To do so, we’ll create an interface that describes our constraint.Here, we’ll create an interface that has a single .length property and then we’ll use this interface and the extends keyword to denote our constraint:

ts

interface Lengthwise {

length: number;

}

function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {

console.log(arg.length); // Now we know it has a .length property, so no more error

return arg;

}

Try

Because the generic function is now constrained, it will no longer work over any and all types:

ts

loggingIdentity(3);

Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.2345Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.Try

Instead, we need to pass in values whose type has all the required properties:

ts

loggingIdentity({ length: 10, value: 3 });

Try

Using Type Parameters in Generic Constraints

You can declare a type parameter that is constrained by another type parameter.For example, here we’d like to get a property from an object given its name.We’d like to ensure that we’re not accidentally grabbing a property that does not exist on the obj, so we’ll place a constraint between the two types:

ts

function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {

return obj[key];

}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a");

getProperty(x, "m");

Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.2345Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.Try

Using Class Types in Generics

When creating factories in TypeScript using generics, it is necessary to refer to class types by their constructor functions. For example,

ts

(Video) Java Generics Tutorial

function create<Type>(c: { new (): Type }): Type {

return new c();

}

Try

A more advanced example uses the prototype property to infer and constrain relationships between the constructor function and the instance side of class types.

ts

class BeeKeeper {

hasMask: boolean = true;

}

class ZooKeeper {

nametag: string = "Mikle";

}

class Animal {

numLegs: number = 4;

}

class Bee extends Animal {

numLegs = 6;

keeper: BeeKeeper = new BeeKeeper();

}

class Lion extends Animal {

keeper: ZooKeeper = new ZooKeeper();

}

function createInstance<A extends Animal>(c: new () => A): A {

return new c();

}

createInstance(Lion).keeper.nametag;

createInstance(Bee).keeper.hasMask;

Try

This pattern is used to power the mixins design pattern.

Generic Parameter Defaults

Consider a function that creates a new HTMLElement. Calling the function with no arguments generates a Div; calling it with an element as the first argument generates an element of the argument’s type. You can optionally pass a list of children as well. Previously you would have to define it as:

ts

declare function create(): Container<HTMLDivElement, HTMLDivElement[]>;

Cannot find name 'Container'.2304Cannot find name 'Container'.

declare function create<T extends HTMLElement>(element: T): Container<T, T[]>;

Cannot find name 'Container'.2304Cannot find name 'Container'.

declare function create<T extends HTMLElement, U extends HTMLElement>(

element: T,

children: U[]

): Container<T, U[]>;

Cannot find name 'Container'.2304Cannot find name 'Container'.
Try

With generic parameter defaults we can reduce it to:

ts

declare function create<T extends HTMLElement = HTMLDivElement, U = T[]>(

element?: T,

(Video) Generics o Branded Drugs A Short Documentation

children?: U

): Container<T, U>;

Cannot find name 'Container'.2304Cannot find name 'Container'.Try

A generic parameter default follows the following rules:

  • A type parameter is deemed optional if it has a default.
  • Required type parameters must not follow optional type parameters.
  • Default types for a type parameter must satisfy the constraint for the type parameter, if it exists.
  • When specifying type arguments, you are only required to specify type arguments for the required type parameters. Unspecified type parameters will resolve to their default types.
  • If a default type is specified and inference cannot choose a candidate, the default type is inferred.
  • A class or interface declaration that merges with an existing class or interface declaration may introduce a default for an existing type parameter.
  • A class or interface declaration that merges with an existing class or interface declaration may introduce a new type parameter as long as it specifies a default.

FAQs

What is a good reason to write a generic method? ›

In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs.

Why not to use generics? ›

The biggest challenge with Generics is, it's bit tricky to get used to with it and hence many programmer find generics not readable code.

Can you give an example of a generic method? ›

For static generic methods, the type parameter section must appear before the method's return type. The complete syntax for invoking this method would be: Pair<Integer, String> p1 = new Pair<>(1, "apple"); Pair<Integer, String> p2 = new Pair<>(2, "pear"); boolean same = Util. <Integer, String>compare(p1, p2);

What exactly does generic type mean? ›

Definition: “A generic type is a generic class or interface that is parameterized over types.” Essentially, generic types allow you to write a general, generic class (or method) that works with different types, allowing for code re-use.

How to mock a generic method? ›

To mock a generic class with Mockito, you'll need to do the following: Create a mock object of the generic class using the Mockito. mock() method. Set up the desired behavior of the mock object using Mockito's when() and thenReturn() methods.

When should you use generics? ›

Use generic types to maximize code reuse, type safety, and performance. The most common use of generics is to create collection classes. The . NET class library contains several generic collection classes in the System.

What are generic good examples? ›

Types of Generic Brands

Dairy products. Snacks such as cookies and potato chips. Canned products such as soup, fruit, and vegetables.

What are examples of generic statements? ›

Generics are statements such as “tigers are striped”, “a duck lays eggs”, “the dodo is extinct”, and “ticks carry Lyme disease”. Generics express generalizations, but unlike quantified statements, generics do not carry information about how many members of the kind or category have the property.

What is an example sentence for generic? ›

Examples from Collins dictionaries

They encourage doctors to prescribe cheaper generic drugs. Brand names only are given, as generics are not usually prescribed. Generic drugs are as effective as those with brand names. Doctors sometimes prescribe cheaper generic drugs instead of more expensive brand names.

Why is it called generic? ›

Under a patent, other companies cannot sell a similar medicine that contains the same active ingredient. After the patent expires, other companies are allowed to develop medicines based on the active ingredient. These are known as 'generic' medicines.

What is difference between generic and standard? ›

Generic medicines usually cost less than non-generic medicines, mainly because they don't have to repeat clinical trials and studies. The branded non-generic medicine has performed the required tests to prove its effectiveness and safety. Generic medicines are cheaper, but they adhere to the same quality standards.

What is the biggest advantage of generics? ›

Generics shift the burden of type safety from you to the compiler. There is no need to write code to test for the correct data type because it is enforced at compile time. The need for type casting and the possibility of run-time errors are reduced. Better performance.

What is the disadvantage of generics? ›

According to oracle documentation, the following points are the disadvantage of generics: Cannot instantiate Generic types with primitive types. Cannot create instances of type parameters. Cannot declare static fields whose types are type parameters.

Are generics good or bad? ›

Bioequivalent – Generic medicines use the same active ingredients as non-generic medicines and have the same risks and effectiveness. Generic medicines offer equally high-quality and effective treatment as non-generic medicines but at much lower prices.

How do generic types work? ›

A generic type is a class or interface that is parameterized over types, meaning that a type can be assigned by performing generic type invocation, which will replace the generic type with the assigned concrete type.

What are methods with generics? ›

Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used.

How do you create a generic variable? ›

Creating a simple generic type is straightforward. First, declare your type variables by enclosing a comma-separated list of their names within angle brackets after the name of the class or interface. You can use those type variables anywhere a type is required in any instance fields or methods of the class.

What is the golden rule of generics? ›

Rule: If a type parameter only appears in one location, strongly reconsider if you actually need it.

Why are generics used 1? ›

1. Why are generics used? Explanation: Generics add stability to your code by making more of your bugs detectable at compile time.

Can generics be used on methods and classes? ›

Java Generics Bounded Type Parameters

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

What is a generic response? ›

A generic response is a rejection. Rejection hurts. It provokes feelings of anger, frustration and fear. It encourages revenge under the right circumstances.

What is an example of generic in business? ›

Many supermarket chains have their own generics. Generics, in this sense, means goods with the supermarket's name on them. They sell them more cheaply than products with brand names. For example, retailers have their own generic sodas, which say 'Cola,' rather than having a brand name like Pepsi or Coke.

What are 3 examples of a specific statement? ›

Statistics, logical reasons, examples, and expert testimonies are all examples of specific statements.

Which word or phrase best expresses the meaning of generic? ›

The correct answer is 'Universal. ' Key Points. The given word 'Generic' means belonging or relating to the whole group or class; not specific. ( पूरे समूह या वर्ग से संबंधित; अविशिष्‍ट)

What is an example of generic and specific name? ›

For instance, in Panthera leo (the binomial name of lion) the Panthera is the generic name (or the genus) whereas the leo is the specific epithet.

Does generic mean original? ›

How are generics different from the original name brand? According to the U.S. Food and Drug Administration (FDA), generic drugs are no different than the branded version. They are carefully created to have the same quality, safety and effectiveness.

Is Tylenol generic or brand? ›

Acetaminophen (Tylenol) is available as a generic medication and may be significantly cheaper compared to the brand version.

Does generic mean unique? ›

A generic product, whether it's a tire or donut or drug, is typical of all other products like it. There's nothing distinctive or unique about it.

Is generic and common the same? ›

Common nouns refer to people, places, or things without using their name or title. They are the opposite of proper nouns, and all nouns are either common or proper. Technically generic nouns are common nouns, but not all common nouns are generic nouns.

What are the advantages of generic methods in Java? ›

Advantage of Java Generics
  • Type-safety: We can hold only a single type of objects in generics. It doesn?t allow to store other objects. ...
  • Type casting is not required: There is no need to typecast the object. ...
  • Compile-Time Checking: It is checked at compile time so problem will not occur at runtime.

When to use generic method Java? ›

Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used. It is possible to use both generic methods and wildcards in tandem.

What is an advantage of using generic types quizlet? ›

What is the key benefit of using generics? The key benefit generics is to allow errors to be detected at compile time rather than at runtime (like exception handling).

What are the benefits of generics in collection framework? ›

What is the benefit of Generics in Collections Framework? Java 1.5 came with Generics and all collection interfaces and implementations use it heavily. Generics allow us to provide the type of Object that a collection can contain, so if you try to add any element of other type it throws compile time error.

What are two limitations of generics in Java? ›

To use Java generics effectively, you must consider the following restrictions: Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters. Cannot Declare Static Fields Whose Types are Type Parameters.

How does a generic method differ from a generic type? ›

From the point of view of reflection, the difference between a generic type and an ordinary type is that a generic type has associated with it a set of type parameters (if it is a generic type definition) or type arguments (if it is a constructed type). A generic method differs from an ordinary method in the same way.

Can we overload a generic method in Java? ›

A generic method can also be overloaded by nongeneric methods. When the compiler encounters a method call, it searches for the method declaration that best matches the method name and the argument types specified in the call—an error occurs if two or more overloaded methods both could be considered best ...

What is the difference between generic and interface in Java? ›

Interfaces make your design more flexible/decoupled. Whereas Generics, implement type safety and enforce you to pass around a specific type of class.

Can you give an example of a generic method in Java? ›

For example, // creating a string type ArrayList ArrayList<String> list1 = new ArrayList<>(); // creating a integer type ArrayList ArrayList<Integer> list2 = new ArrayList<>(); In the above example, we have used the same ArrayList class to work with different types of data.

What is one of the disadvantages of generic? ›

The Cons of Generic Drugs

Risk of sensitivity or intolerance: By law, the active ingredient in a generic drug must be the same as the original drug, but generics may include different inactive ingredients such as preservatives or fillers.

Which of these types Cannot be used as a generic type? ›

1. Which of these types cannot be used to initiate a generic type? Explanation: None.

Which of the following statements is valid about advantages of generics? ›

Which of the following statements is valid about advantages of generics? Generics shift the burden of type safety to the programmer rather than compiler. Generics require use of explicit type casting. Generics provide type safety without the overhead of multiple implementations.

What are generics and which problem do they solve? ›

In a nutshell, generics solves the problem of having to use loosely typed objects. For example, consider ArrayList vs List<T> . It allows you to have a strongly typed collection. list[0] will return type T vs arrayList[0] which will return type object .

Which one is faster collections or generics? ›

In most cases, it is recommended to use the generic collections because they perform faster than non-generic collections and also minimize exceptions by giving compile-time errors.

Which one is faster collections or generics in Java? ›

The java generics with other classes rather than the collection classes is the easiest way to show the basics of Java generics, but it's the quickest way to show the basics of Java generics with referencing and de-referencing its using settings for the generic type of a Collection and other classes like HashSet, ...

Videos

1. Design Self-documenting Types to Avoid Bugs
(Zoran Horvat)
2. Programming Concepts: Generics
(Recursive)
3. Applicative Parsing with Documentation – Chris Eidhof
(Functional Swift)
4. Having fun with Generics and Abstract classes in C# - Don Wibier - NDC London 2022
(NDC Conferences)
5. Java generics ❓
(Bro Code)
6. ZuriHac 2016: Generic (and type-level) Programming with Generics-sop
(Google TechTalks)

References

Top Articles
Latest Posts
Article information

Author: Terence Hammes MD

Last Updated: 10/09/2023

Views: 5799

Rating: 4.9 / 5 (69 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Terence Hammes MD

Birthday: 1992-04-11

Address: Suite 408 9446 Mercy Mews, West Roxie, CT 04904

Phone: +50312511349175

Job: Product Consulting Liaison

Hobby: Jogging, Motor sports, Nordic skating, Jigsaw puzzles, Bird watching, Nordic skating, Sculpting

Introduction: My name is Terence Hammes MD, I am a inexpensive, energetic, jolly, faithful, cheerful, proud, rich person who loves writing and wants to share my knowledge and understanding with you.