Description
After reading the Comparing two functions section of the handbook I got myself pretty confused and concerned. I have an example below that I think (taken to the prepare-for-duck-typing-extreme) means I should code every class's method as if all of its parameters are optional (even though they're not defined as such).
TypeScript Version:
1.8.10 / next (1.9.0-dev.20160624-1.0)
Code
(function () { "use strict";
class C1 { one(...hi: string[]) { } }
class C2 { one(hi: string) { hi.length; } }
function Test() {
const c2 = new C2();
const c2as1: C1 = c2; // BAD assignment
// TypeError: Cannot read property 'length' of undefined
c2as1.one(); // BAD execution
// error TS2346: Supplied parameters do not match any signature of call target.
//c2.one();
// error TS2345: Argument of type 'undefined' is not assignable to parameter of type 'string'.
// Happens once you enable TypeScript 2.0's --strictNullChecks.
//c2as1.one(void 0);
//c2.one(void 0);
}
})();
Actual behavior:
I have to remember to write run-time checking of typeof hi === "string" ? hi.length : 0
instead of the simple/easy hi.length
inside my C2#one(hi: string)
method to prevent against a TypeError.
Expected behavior:
I'd love for there to be some way for TypeScript to stop the BAD assignment
line above; maybe one that turns off 'discarding' parameters altogether?
The defense given for discarding parameters is a signature like Array#forEach
-- where callers commonly omit the 2nd/3rd parameters to the callbackfn
. That doesn't make sense to me though, why isn't the *.d.ts for Array#forEach
just defined as:
forEach(callbackfn: (value?: T, index?: number, array?: T[]) => void, thisArg?: any): void;
Instead of how it is?
forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;
Maybe my targeting of parameter discarding is too strong, but it really seems like there should be some way to configure TypeScript to block the assertion of a C2
instance to a C1
interface without requiring me to just write better code like:
class betterC1 { one(hi: string, ...restHi: string[]) { } }