Sometimes when using external libraries you will find that interfaces aren’t correctly defined. This happened to me today using React Helmet. The Helmet class has the following definition:
export class Helmet extends React.Component<HelmetProps> {
static peek(): HelmetData
static rewind(): HelmetData
static renderStatic(): HelmetData
static canUseDOM: boolean
}
export interface HelmetData {
base: HelmetDatum
bodyAttributes: HelmetHTMLBodyDatum
htmlAttributes: HelmetHTMLElementDatum
link: HelmetDatum
meta: HelmetDatum
noscript: HelmetDatum
script: HelmetDatum
style: HelmetDatum
title: HelmetDatum
titleAttributes: HelmetDatum
}
However, running typescript±console.log(Helmet.peek())
returns the following output:
{
"baseTag": [],
"bodyAttributes": {},
"defer": true,
"encode": true,
"htmlAttributes": { "lang": "en" },
"linkTags": [],
"metaTags": [
{ "name": "description", "content": "passed description" },
{ "name": "twitter:card", "content": "summary" },
{ "name": "twitter:creator", "content": "author" },
{ "name": "twitter:title", "content": "site title" },
{ "name": "twitter:description", "content": "passed description" }
],
"noscriptTags": [],
"onChangeClientState": [Function(anonymous)],
"scriptTags": [],
"styleTags": [],
"title": "passed title | site title",
"titleAttributes": {}
}
This is annoying as I have to access the metaTags property to write unit tests (see highlighted lines above). Running the following code
const helmet = Helmet.peek();
console.log(helmet.metaTags);
causes TypeScript to throw TS2339 errors (see below) as according to the interface metaTags doesn’t exist
TS2339: Property ‘metaTags’ does not exist on type ‘HelmetData’.
So what is to be done? Luckily in TypeScript one can use type assertions. According to the documentation:
Sometimes you’ll end up in a situation where you’ll know more about a value than TypeScript does. Usually this will happen when you know the type of some entity could be more specific than its current type.
Type assertions are a way to tell the compiler “trust me, I know what I’m doing.” A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler. TypeScript assumes that you, the programmer, have performed any special checks that you need.
The quick fix to prevent TS2339 errors in this case is to use the following code snippet:
interface RealHelmetData extends HelmetData {
metaTags: [
{
name: string;
content: string;
},
];
}
const helmet = Helmet.peek() as RealHelmetData;
Pretty basic stuff but hopefully this will help someone else out who encounters this issue. I might write a short tutorial on how to properly unit test Helmet with Jest in the future.