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()
.
A type guard is a TypeScript technique used to get information about the type of a variable, usually within a conditional block. Type guards are regular functions that return a boolean, taking a type and telling TypeScript if it can be narrowed down to something more specific.
To declare a function that throws an error, set its return type to never . The never type is used for functions that never return a value, in other words functions that throw an exception or terminate execution of the program. Copied! The never type is used very rarely in TypeScript.
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
Playground Link
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With