I have a utility function to check whether a variable is not null or undefined, and I want TypeScript to narrow down the input variable if it passes the check, for example:
public init(input?: string): void {
function isSpecified(input: any): boolean {
return (typeof input !== "undefined") && (input !== null);
}
if (isSpecified(input)) {
let copiedString: string = input; // <-- Error; input is still 'string | undefined'
}
}
As you can see TS is not removing the possibility of the string being undefined
even though the function makes that logically impossible. Is there a way I can get this function call to narrow down input
inside the if
block?
You can use a generic type guard function:
public init(input?: string): void {
function isSpecified<T>(input: null | undefined | T): input is T {
return (typeof input !== "undefined") && (input !== null);
}
if (isSpecified(input)) {
let copiedString: string = input; // OK
}
}
Note that if TypeScript narrows down a variable's union type through narrowing during an assignment, isSpecified
will still not act as a type guard. For example, in the following code, TS will give an error:
someMethod = () => {
const foo: undefined | null | number = undefined;
if (isSpecified(foo)) {
this.nonNullValue = foo; // Error
}
};
In the above, foo
being assigned as undefined
narrows the variable type and the T
in isSpecified
is undefined
, so TS still doesn't treat foo
as definitely being specified. This can be worked around by using a type assertion (val as ...
) to prevent narrowing:
someMethod = () => {
//const foo = 123 as
// ... or:
const foo = undefined as
undefined | null | number;
if (isSpecified(foo)) {
this.nonNullValue = foo;
}
};