Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript generic type parameters: T vs T extends {}

Is there functionally any difference between the two generic type parameters below?.

function funcA<T>() { }
function funcB<T extends {}>() {}

I have seen them both used and am confused as to the differences?

like image 711
kimsagro Avatar asked May 07 '20 01:05

kimsagro


People also ask

What is T in TypeScript type?

This article opts to use the term type variables, coinciding with the official Typescript documentation. T stands for Type, and is commonly used as the first type variable name when defining generics. But in reality T can be replaced with any valid name.

How do you pass a generic type as parameter in TypeScript?

Assigning Generic ParametersBy 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 generic types extend generic types?

We can add generic type parameters to class methods, static methods, and interfaces. Generic classes can be extended to create subclasses of them, which are also generic.

How do you determine what type a generic parameter T is?

You can get the Type that represents T , and use the IsInterface property: Type type = typeof(T); if (type. IsInterface) { ... } If you want to know which interface is passed, just use == to compare the Type objects, e.g.


2 Answers

Note: I'll assume you're using a version of TypeScript 3.5 or later; in TypeScript 3.5 a change was made so that generic type parameters are implicitly constrained by unknown instead of the empty object type {}, and some minor details about the difference between funcA() and funcB() changed. I don't want to make a long post even longer by talking about how things used to be in TS3.4 and below.


If you don't explicitly constrain a generic type parameter via extends XXX, then it will implicitly be constrained by unknown, the "top type" to which all types are assignable. So in practice that means the T in funcA<T>() could be absolutely any type you want.

On the other hand, the empty object type {}, is a type to which nearly all types are assignable, except for null and undefined, when you have enabled the --strictNullChecks compiler option (which you should). Even primitive types like string and number are assignable to {}.

So compare:

function funcA<T>() { }
funcA<undefined>(); // okay
funcA<null>(); // okay
funcA<string>(); // okay
funcA<{ a: string }>(); // okay

with

function funcB<T extends {}>() { }
funcB<undefined>(); // error
funcB<null>(); // error
funcB<string>(); // okay
funcB<{ a: string }>(); // okay

The only difference is that T extends {} forbids null and undefined.


It might be a little confusing that {}, a so-called "object" type, would accept primitives like string and number. It helps to think of such curly-brace-surrounded types like {} and {a: string} as well as all interface types not necessarily as "true" object types, but as types of values where you can index into them as if they were objects without getting runtime errors. Primitives except for null and undefined are "object-like" in that you can treat them as if they were wrapped with their object equivalents:

const s: string = "";
s.toUpperCase(); // okay

And therefore even primitives like string are assignable to curly-brace-surrounded types as long as the members of those types match:

const x: { length: number } = s; // okay

If you really need to express a type that only accepts "true", i.e., non-primitive objects, you can use the object:

const y: object & { length: number } = s; // error
const z: object & { length: number } = { length: 10 }; // okay

But I (seriously) digress.


Okay, hope that helps; good luck!

Playground link to code

like image 110
jcalz Avatar answered Oct 12 '22 19:10

jcalz


Yes. In funcB, T must extend {} which means pretty much anything except null and undefined. T can be a primitive though.

like image 25
Robert Moore Avatar answered Oct 12 '22 17:10

Robert Moore