I have a class that uses the same type guard in multiple functions; something like this:
function validData(d: Data | null): d is Data {
return d !== null;
}
class C {
data: Data | null;
public doA() {
if (!validData(this.data))
throw new Error("Invalid data");
/* … */
}
public doB() {
if (!validData(this.data))
throw new Error("Invalid data");
/* … */
}
}
Can I refactor this code to move the error into the type guard? Something like this:
function assertData(d: Data | null): ??? {
if (d === null)
throw new Error("Invalid data");
}
…which I could use like this:
class C {
data: Data | null;
public doA() {
assertData(this.data);
/* … */
}
public doB() {
assertData(this.data);
/* … */
}
}
Currently I'm using the following workaround:
function must(d: Data | null): Data {
if (d === null)
throw new Error("Invalid data");
return d;
}
… but this forces me to wrap every access to this.data
in must()
.
Edit Since the original answer, typescript has added the ability for custom type assertions in this PR
type Data = { foo: string };
function assertData(d: Data | null): asserts d is Data {
if (d == null)
throw new Error("Invalid data");
}
// Use
declare var bar: Data | null;
bar.foo // error as expected
assertData(bar)
bar.foo // inferred to be Data
Original answer
Unfortunately the current syntax for type guards requires an if
statement for them to work. So this works
type Data = { foo: string };
function assertData(d: Data | null): d is Data {
if (d == null)
throw new Error("Invalid data");
return true;
}
// Use
let bar: Data | null = null;
if (assertData(bar)) {
bar.foo // inferred to be Data
}
But there is no way to get this to work:
let bar: Data | null = null;
assertData(bar);
bar.foo // bar will still be Data | null