TypeScript Version: 3.7.0-dev.20191016
Search Terms: assertion signatures, asserts, asserts is type
Code
function isString1(val: any): asserts val is string {
if (typeof val !== "string") throw "Nope"
}
const isString2 = (val: any): asserts val is string => {
if (typeof val !== "string") throw "Nope"
}
const x: any = "3";
isString1(x);
isString2(x);
x.toUpperCase();
Expected behavior:
Compiles, infers that x is a string, both when using only isString1 or isString2
Actual behavior:
Compile error on isString2:
Assertions require every name in the call target to be declared with an explicit type annotation.(2775)
Playground Link: 1⃣ playground
Related Issues: #33743
Context
In principle the above problem is easy to work around, however, the result of it is when type checkers are stored on objects, the above error returns as is demonstrated in 2⃣ this playground. Note how the very same function fails when it is stored in an object, unless the type is provided explicitly.
This is (perhaps unfortunately) working as intended, as per #33622.
Thanks for looking into it! Nothing I cannot work around in the end. Just felt surprising / inconsistent :)
As mentioned here (https://github.com/microsoft/TypeScript/pull/33622#issuecomment-575301357) a workaround is:
const isString2: (val: unknown) => asserts val is string = (val) => {
if (typeof val !== "string") throw new Error ("Nope");
};
const x: unknown = "3";
isString2(x);
x.toUpperCase();
Most helpful comment
Thanks for looking into it! Nothing I cannot work around in the end. Just felt surprising / inconsistent :)