Type checking external code
There is no relationship between the TypeScript source code and the JavaScript outputs that gets executed at run-time. TypeScript is only effective at catching compile-time errors if the compiled types match the run-time types.
Normally, this isn't a problem. But in scenarios where you call out to external code (i.e. AJAX call to fetch data from the server), there is no guarantee that the response will be the type you expect. So you must be cautious in these scenarios.
Your specific example
I suspect that your code has a variable jwt
with type any
and you just assigned the type to { id: string, auth_token: string, expires_in }
when in fact, jwt
was of type string as far as javascript is concerned.
In this case, you already found your solution, JSON.parse(str)
. This converts the json string into a javascript object.
Now that you have an object, you can use duck typing to infer the run-time type and let typescript know about the type at compile-time via type guards.
Solution
function isDate(obj: any): obj is Date {
return typeof obj === 'object' && 'toISOString' in obj;
}
function isString(obj: any): obj is string {
return typeof obj === 'string';
}
interface JWT {
id: string;
auth_token: string;
expires_in: Date;
}
function isJwt(obj: any): obj is JWT {
const o = obj as JWT;
return o !== null
&& typeof o === 'object'
&& isString(o.id)
&& isString(o.auth_token)
&& isDate(o.expires_in);
}
function print(jwt: any) {
if (typeof jwt === 'string') {
try {
jwt = JSON.parse(jwt);
} catch (e) {
console.error(`String is not JSON: ${jwt}`);
}
}
if (isJwt(jwt)) {
console.log(`Found jwt: ${jwt.id} ${jwt.auth_token} ${jwt.expires_in}`);
} else {
console.error(`Object is not of type jwt: ${jwt}`);
}
}
print(42);
print('failing');
print(null);
print(undefined);
print({});
print({ id: 'id01', auth_token: 'token01', expires_in: new Date(2018, 11, 25) });
Playground
Try running that code on the TS Playground to see how it inspects the object at run-time.