I often read about assertions as something that should happen in debugging. Is it good practice to use TypeScript assertions in practice? If not, why not?
Below is an example where I would like to use an assertion in production.
The type of win needs to be BrowserWindow | null because the variable is declared before the BrowserWindow is created and assigned. But at the point in the code where I use assertIsBrowserWindow, I expect that win is now of type BrowserWindow, otherwise something has gone horribly wrong. assertIs* seems like a nice syntax to me here.
let win: BrowserWindow | null = null;
function createWindow() {
win = new BrowserWindow();
win.webContents.on("did-finish-load", () => {
assertIsBrowserWindow(win);
win.show();
win.maximize();
});
}
function assertIsBrowserWindow(val: any): asserts val is BrowserWindow {
if (!(win instanceof BrowserWindow)) {
throw new Error("Expected window");
}
}
Here is another example:
// The only allowed values for an input group is FileSystemEntryType values.
<input
type="radio"
value={FileSystemEntryType.Directory}
checked={state.selectionMode === FileSystemEntryType.Directory}
onChange={onSelectionModeChanged}
/>
// The onChange handler receives a string in the event, since coming from HTML world, the value can be any string. I had a switch case statement before that defaulted to an error. Now I use the shorter assert syntax instead.
const onSelectionModeChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
const selectionMode = Number.parseInt(e.currentTarget.value);
assertIsFileSystemEntryType(Number.parseInt(e.currentTarget.value));
dispatch({ type: "UPDATE_SELECTION_MODE", selectionMode: selectionMode });
};
// Supporting code
export enum FileSystemEntryType {
File,
Directory,
}
export function assertIsFileSystemEntryType(val: any): asserts val is FileSystemEntryType {
if (!Object.values(FileSystemEntryType).includes(val)) {
throw new Error(`Expected ${val} to have type FileSystemEntryType`);
}
}