Skip to content

TypeScript Interfaces Do Not Provide Type Safety

TypeScript interfaces are a way to define the shape of an object and they’re pretty commonly used through-out any real-world projects and production applications. However, they may also give a false sense of security when types are more structured and complex in this way - a formal interface.

TypeScript Interfaces Are Not Enforced at Runtime

TypeScript expects to uphold the following generic interface which you may recognize from the Express.js library for handling HTTP requests:

(alias) interface Request<P = core.ParamsDictionary,
ResBody = any,
ReqBody = any,
ReqQuery = qs.ParsedQs,
Locals extends Record<string, any> = Record<string, any>>
import Request

Let’s say you’re building on-top of this HTTP function handler interface, as follows:

interface UserComponentQueryString {
name?: string;
}
class UserController {
public getUserHelloComponent: RequestHandler = async (
_req: Request<{}, {}, {}, UserComponentQueryString>,
res: Response) => {
const userName = _req.query.name || "World";
const helloComponent = `<h1>Hello, ${userName}!</h1>`;
return res.send(helloComponent);
}
}

What happens if the name query parameter is not a string? What if it’s an array of strings or an object? TypeScript interfaces do not provide type safety at runtime, so the following request will still be evaluated as-is by the Express route handler:

Terminal window
$ curl -G -X 'GET'
-H 'accept: application/json'
"http://localhost:8080/users/component"
--data-urlencode "name[]=<img src=x onError=alert(1) />"
<h1>Hello, <img src=x onError=alert(1) />!</h1>