Contained in this section is a singular entity that displays varying behavior based on whether it is invoked with the keyword new
. This capability exists within Javascript, though it may introduce complexity into your codebase; encountering such a signature is likely to be rare, occurring mainly when updating an ancient or highly adaptable Javascript library for use with Typescript.
(The behavior doesn't necessarily have to differ: Well-designed entities can be callable with or without new
, exhibiting consistent behavior in both cases and necessitating both call and construct signatures. However, intentional flexibility of this nature remains atypical. Thanks @kaya3!)
The example you provided appears in Further Insights on Functions alongside this statement:
Certain entities, like the Date
object in JavaScript, are capable of being called with or without new
. You can mix call and construct signatures within a given type arbitrarily:
This pertains to the pre-existing Date object, which is detailed in this reference from MDN:
Date()
When utilized as a function, returns a string representation of the current date and time, identical to what new Date().toString()
accomplishes.
new Date()
When employed as a constructor, generates a fresh instance of the Date
object.
console.log(typeof Date()) // string
console.log(typeof new Date()) // object
As previously mentioned, it's quite uncommon for a single Function object to fulfill both roles: Typically, a function/class will be intentionally designated for either approach, not both simultaneously. Nevertheless, due to its feasibility in Javascript (even implemented in built-in objects), TypeScript must be equipped to depict an entity that functions across both invocation styles.
interface CallOrConstruct {
new (s: string): Date; // construct
(n?: number): number; // call
}
// construct
let object: Date = new CallOrConstruct("optional string s");
// call
let myNumber: number = CallOrConstruct(/* n= */ 42);
You're unlikely to encounter a need to define an interface similar to this, especially if you adhere to using class
and constructor
for classes, and function
(or other standard function declarations) for your functions. Such interfaces are typically reserved for scenarios where nonstandard TypeScript types require declaration (such as within a .d.ts
file for external Javascript libraries), or if you're experimenting with creating a clever and intricate TypeScript entity that can operate interchangeably. Personally, I haven't found a need to craft my own interface like this, although I've come across a few instances within library implementations and associated typings.