'how to implement new constructor definition and normal constructor def at same time in typescript
When we both use new constructor definition and normal constructor definition in ts, how to implement the function to make ts pass? I try to use function to implement the definition, but it failed, ts can't understand what i am doing
interface Date1 {
x: number
}
interface Date1Constructor {
new(s: string): Date1
(n: number): number
}
// if use class, we can't implement constructor without new
// class Date1Imple implements Date1 {
// constructor(s:string) {
// }
// }
// or
// if use function, how to make ts know what we are doing makes sense
// function Date1Imple(param: string): Date1;
// function Date1Imple(param: number): number; and
// function Date1Imple(param: string | number): Date1 | number {
// if(this){
// if (typeof param === 'string') {
// return {
// x: 2
// }
// }
// }
// if (typeof param === 'number') {
// return 2
// }
// }
function test(a: Date1Constructor) {
}
test(Date1Imple)
Solution 1:[1]
The implementation signature of an overloaded function is never 100% compatible with a strict interpretation of all of the overloads. Since the implementation signature isn't included in the options available at the call site, that's okay, and we can use a gentle as Date1Constructor at the end to say it's okay to TypeScript. As with any type assertion, though, it's important to triple-check that your logic matches the assertion you're making.
In this case, we can differentiate between a new call and a non-new call via new.target (in modern environments). In a new call, only a string argument is allowed; in a non-new call, only a number is allowed:
const Date1Imple = function (param: string | number) {
if (new.target) {
if (typeof param !== "string") {
throw new Error(`Invalid invocation, 'new Date1Imple(x)' requires a string argument.`);
}
return {
x: 2
};
}
if (typeof param !== "number") {
throw new Error(`Invalid invocation, 'Date1Imple(x)' requires a number argument.`);
}
return 2;
} as Date1Constructor;
That produces the desired behavior and offers the desired signatures:
// Works, typeof `dt` is `string`
const dt = new Date1Imple("x");
// Works, typeof `num` is `number`
const num = Date1Imple(42);
// Fails as expected, the `new` signature doesn't allow a `number` argument
const dt2 = new Date1Imple(42);
// Fails as expected, the non-`new` signature doesn't allow a `string` argument
const num2 = Date1Imple("42");
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | T.J. Crowder |
