Reputation: 9805
In order to write more robust code, I'm looking at using TypeScript for my web based projects. I have relatively little experience with the language thus far, but I have run into a problem that I'm having difficulty searching for.
Consider the TypeScript code below:
public static getResponseCode(resObj: object): number {
let c: number = resObj["c"]
return c;
}
Is there a way that I can force the TypeScript compiler to pull me up here and tell me that resObj["c"]
may not be a number and that I need to first check if it is a number? E.g. can I force TypeScript to make me rewrite the code as this (or something similar)?:
public static getResponseCode(resObj: object): number {
if (typeof resObj["c"] !== "number") { return APIResponseCode.UnknownFailure; }
let c: number = resObj["c"]
return c;
}
I expect I'm getting the results that I am simply because the type of resObj["c"]
is any
. What can I do here? Is there a common pattern used in TypeScript?
Upvotes: 3
Views: 3279
Reputation:
TypeScript does no run-time type-checking. Depending on what you are trying to do, you have a couple of options. The first is to define an interface for resObj
:
interface ResObj { c: number; }
Now
public static getResponseCode(resObj: ResObj): number {
let c: number = resObj.c;
return c;
}
Your code will not compile now if you pass getResponseCode
something that does not match ResObj
(with a c
property which is not a number).
What if you want c
to be maybe a number, or maybe a string? In that case, use a union type:
interface ResObj { c: number | string; }
Your original version of getResponseCode
above will now fail to compile. TypeScript will complain that it does not know how to convert string | number
into number
.
If you write the code as you proposed:
public static getResponseCode(resObj: ResObj): number {
if (typeof resObj.c !== "number") { return APIResponseCode.UnknownFailure; }
let c: number = resObj.c;
return c;
}
TypeScript will be happy, since its flow analysis detects the typeof
check and knows that by the time it reaches the return
statement c
can only be a number.
For more complex situations, you can use what is called a type guard, which tells TypeScript explicitly that a particular function guarantees a particular type of its parameter:
function isNumber(c: string | number): c is number {
return typeof c === 'number';
}
Now you can write
public static getResponseCode(resObj: ResObj): number {
if (!isNumber(resObj.c)) { return APIResponseCode.UnknownFailure; }
let c: number = resObj.c;
return c;
}
Upvotes: 2
Reputation: 141512
You can turn on the noImplicitAny
compiler option. The compiler will then complain any time something is implicitly any.
We set noImplictAny inside tsconfig.json
.
{
"compilerOptions": {
"noImplicitAny": true
}
}
Or we set it like this tsc --noImplicitAny
from the command line.
That would force you to do something.
For instance, you could use any explicitly.
public static getResponseCode(resObj: object): number {
const resAny = resObj as any;
if (resAny.c && typeof resAny.c !== "number") {
return APIResponseCode.UnknownFailure;
}
const c: number = resAny.c;
return c;
}
Or you could use an interface with a union type and a type guard.
interface ResObj {
c: boolean | string | number | object;
}
public static getResponseCode2(resObj: ResObj): number {
if (typeof resObj.c !== "number") {
return APIResponseCode.UnknownFailure;
}
const c: number = resObj.c;
return c;
}
Upvotes: 2