Should you be seeking TypeScript to automatically generate runtime type guards, that functionality is not available. Nonetheless, the compiler does a commendable job of narrowing types based on your knowledge of the object being examined. Take, for example, a scenario where you are certain that something is either a TEST_OBJECT
or a string
:
function hasKey<K extends string>(k: K, x: any): x is Record<K, {}> {
return k in x;
}
declare const obj: TEST_OBJECT | string;
if (hasKey("test2", obj)) {
// it knows that obj is a TEST_OBJECT now
console.log(obj.test1);
console.log(obj.test2.test3 === false);
} else {
// it knows that obj is a string
console.log(obj.charAt(0));
}
If you lack insight into the nature of the object under examination, @JoshCrozier suggests utilizing User-Defined Type Guards. By constructing these guards similar to how interfaces and types are formed, you can achieve clarity:
function hasKey<K extends string>(k: K, x: any): x is Record<K, {}> {
return k in x;
}
function isTEST_INTERFACE(x: any): x is TEST_INTERFACE {
return hasKey("test3",x) && (typeof x.test3 === 'boolean');
}
function isTEST_TYPE(x: any): x is TEST_TYPE {
return (typeof x === 'string') || (typeof x === 'number');
}
function isTEST_OBJECT(x: any): x is TEST_OBJECT {
return hasKey("test1", x) && isTEST_TYPE(x.test1) &&
hasKey("test2", x) && isTEST_INTERFACE(x.test2);
}
// implementation:
declare const obj: TEST_OBJECT | string
if (isTEST_OBJECT(obj)) {
console.log(obj.test1);
console.log(obj.test2.test3 === false);
} else {
console.log(obj.charAt(0));
}
Trust this information proves useful.