I've noticed that <P extends object>
generic is usually pointless because basically everything in javascript is an object. Most literals are objects with .toString method. A string is an object with a .length property, etc. I've come to prefer just <P>
but curious what others have noticed.
I don't have a good example right now, I'm more just trying to hear about other people's experience.
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.
A generic class has a type parameter enclosed in angle brackets (< >) immediately after the class name. In generic class, the same type parameter can be used to annotate method parameters, properties, return types, and local variables.
TypeScript fully supports generics as a way to introduce type-safety into components that accept arguments and return values whose type will be indeterminate until they are consumed later in your code.
Using generics allows us to write a typesafe code that will work with a wide range of primitives and objects.
See "The object
Type in TypeScript" for more information.
The object
type in TypeScript was introduced specifically to exclude the seven primitive types, string
, number
, boolean
, bigint
, symbol
, undefined
, and null
. (Yes, typeof null === "object"
at runtime, but it is still considered primitive in JS and TS). It is true that string
, number
, boolean
, bigint
, and symbol
values will be automatically wrapped in String
, Number
, Boolean
, BigInt
, and Symbol
objects (respectively) when you access members on them as if they were objects. But they are distinguishable from true objects, and sometimes this makes a difference. The example given in the TypeScript Handbook is the Object.create()
, which leads to runtime errors if passed an argument of a primitive type (except for null
). Hence TypeScript's typing for Object.create()
specifies that its argument is of type object | null
. If you want your generic parameter to exclude primitives, <P extends object>
would be the right way to do it... so it isn't pointless.
Note that there is also an Object
interface in TypeScript, starting with an uppercase O
. This interface contains the (apparent) members that exist on everything in JS, like valueOf()
and toString()
. It might be closer to what you were thinking of when you said "everything is an object"; only null
and undefined
are not assignable to Object
. Generally speaking, though, you probably don't want to use the Object
type in TypeScript; such wrapper types are hardly ever what people want to use.
If you really want to capture "anything which can be indexed into like an object", you should probably use the so-called "empty object" type, {}
. This is an object type with no known properties, and behaves like Object
. Again, only null
and undefined
are not assignable to {}
. In fact, it used to be the case that unconstrained generic type parameters (like <P>
instead of <P extends Q>
) were implicitly constrained to {}
. So it used to be quite literally useless to write <P extends {}>
.
Since TypeScript 3.5, however, unconstrained generics are now given an implicit constraint of unknown
instead of {}
. The unknown
type really is "everything" in TypeScript. You can assign any value whatsoever to a variable of type unknown
(but not vice-versa). It is truly pointless to write <P extends unknown>
.
And we might as well end with any
, the ultimate "anything-goes" type. Not only can you assign anything to any
(like unknown
), you can also assign any
to anything (like never
). Using any
is like throwing up your hands and giving up; it's more of a disabling of type checking than it is an actual type. Since TypeScript 3.9, writing <P extends any>
is the same as writing <P extends unknown>
, and therefore, similarly pointless. (It used to be that <P extends any>
allowed you to treat P
like any
when P
was unresolved, like in a generic function implementation, but that was considered silly and changed.)
Playground link to code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With