Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I'm reading through the code of the
class-validator
library and it has the following
isInstance
method in it:
* Checks if the value is an instance of the specified object.
isInstance(object: any, targetTypeConstructor: new (...args: any[]) => any) {
return targetTypeConstructor
&& typeof targetTypeConstructor === "function"
&& object instanceof targetTypeConstructor;
Any thoughts on how to go about understanding the type
new (...args: any[]) => any
? This is the first time I'm seeing this type of construct ...
Let's reduce the type to smaller, bite size pieces that are more easily understood and then build back up to the full thing.
First, let's drop the
new
from our mind and focus on the latter part of the definition:
(...args: any[]) => any
Next let's forget about the arguments for now:
() => any
Hopefully this is familiar as a function that returns type
any
.
Next we can add back in the args:
(...args: any[]) => any
...args: any[]
is using the Rest Parameters construct which essentially says that there can be any number of parameters of the provided type
any
. Because there are an unknown amount of
any
parameters, the type of the argument is an array of
any
.
So hopefully now it makes sense that this is a function that accepts any amount of arguments (of type
any
) and returns type
any
.
Finally we can add back the
new
keyword to get:
new (...args: any[]) => any
The
new
keyword here specifies that this function can be treated as a class constructor function and called with the
new
keyword.
This gives us the whole picture that the function is
a function that accepts any amount of arguments (of type
any
) that returns type
any
and can be used as a constructor function with the
new
keyword
.
When taken in the context of the API, it is essentially allowing you to pass any class constructor to the function.
Breaking it down into pieces:
This keyword in TypeScript specifies what the constructor should look like, for the given property. Nice explanation here:
https://stackoverflow.com/a/39623422/1678614
.
(...args: any[]) => any
This syntax describe a function type (the constructor is a function).
is the ES6 spread operator. It's shorthand for listing out all array elements one by one.
any[]
means that
args
is an array and it's elements can be of any type.
=> any
specifies the return type of the function. In this case it allows the constructor to return any type.
This type specifies a function that accepts any number of arguments that are
any
type, returns
any
value, and can be invoked with
new
.
A constructor is a special type of function that enforces invocation with the
new
keyword at runtime, but in TypeScript, that can be statically detected, so
targetTypeConstructor
is specifying an arbitrary constructor as the second parameter to
isInstance()
.
To that end, it seems redundant to check
typeof targetTypeConstructor === "function"
as that's already enforced by targetTypeConstructor : new (...args: any[]) => any at compile-time by TypeScript.
If the passed value is null, it is already invalidated by the targetTypeConstructor && ... conditional, which is necessary at runtime to prevent object instanceof targetTypeConstructor from throwing TypeError in the event that targetTypeConstructor is actually null due to Step 4
in §12.10.4 of the ECMAScript Specification:
12.10.4 Runtime Semantics: InstanceofOperator ( V, target )
If Type(target) is not Object, throw a TypeError exception.
Let instOfHandler be ? GetMethod(target, @@hasInstance).
If instOfHandler is not undefined, then
a. Return ToBoolean(? Call(instOfHandler, target, « V »)).
If IsCallable(target) is false, throw a TypeError exception.
Return ? OrdinaryHasInstance(target, V).
Steps 4 and 5 provide compatibility with previous editions of ECMAScript that did not use a @@hasInstance method to define the instanceof operator semantics. If an object does not define or inherit @@hasInstance it uses the default instanceof semantics.
–
–
–
–
Means that the parameter targetTypeConstructor is a function that accepts parameters and can be used as a constructor (you can use with new keyword and create instances). You can pass a simple function or a class that are not abstracts.
For more you can check an example in the Typescript Playground
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.