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)
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");