<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harvtronix</title>
    <description>The latest articles on DEV Community by Harvtronix (@harvtronix).</description>
    <link>https://dev.to/harvtronix</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F734398%2Fd6b946ff-6fa1-4548-a4f3-fee443183f1b.jpeg</url>
      <title>DEV Community: Harvtronix</title>
      <link>https://dev.to/harvtronix</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harvtronix"/>
    <language>en</language>
    <item>
      <title>How to Emulate Firebase Auth</title>
      <dc:creator>Harvtronix</dc:creator>
      <pubDate>Sun, 24 Oct 2021 01:26:27 +0000</pubDate>
      <link>https://dev.to/harvtronix/how-to-emulate-firebase-auth-5ah7</link>
      <guid>https://dev.to/harvtronix/how-to-emulate-firebase-auth-5ah7</guid>
      <description>&lt;p&gt;I was recently building an app in which I was trying to integrate Firebase Authentication and Firebase Realtime Database. But I ran into a problem pretty quickly while I was testing things locally.&lt;/p&gt;

&lt;p&gt;Even though Firebase has a super amazing Emulator Suite for local testing, authentication is not included. To me, this meant that the lovely auth-based Realtime DB rules I'd crafted were impossible to test locally unless I modified my DB rules beforehand. But that doesn't make for a very good permissions test, does it? There is an open issue on &lt;a href="https://github.com/firebase/firebase-tools/issues/1677"&gt;GitHub&lt;/a&gt; for addressing this, but at the time of writing, no solution has yet been included in the emulator suite.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update 2020-10-27:&lt;/strong&gt; Firebase Auth is now part of the Emulator Suite! Upgrade the Firebase CLI to version 8.14.0 or greater to use it. If that's all you were looking for, the rest of this post might not be useful to you, but feel free to keep reading for a more detailed look at Firebase Auth and my general philosophy towards testing and modularization.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I spent a bunch of hours trying to figure out how to string things together with Band-Aids and glue to do something that honestly seems like a pretty basic requirement for DB testing: Test my auth rules in both development and production without modifying the very security model I'm trying to test. After all, who would want to do "real" permissions testing for the first time in a production environment??&lt;/p&gt;

&lt;p&gt;Nothing was working. I was stuck. I missed. &lt;a href="https://youtu.be/02WuLTpe3sI?t=355"&gt;Then I missed again. Then I got sad. I had a popsicle. And then I passed out in the snow.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just kidding on the last few, but what I &lt;em&gt;did&lt;/em&gt; do what have an epiphany in the shower. I do some of my best thinking there. &lt;em&gt;Anyone else? No? Okay. Moving on.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;My app in particular is using Google Login and the Google auth provider, so that's what I'm going to focus on here, but I believe this approach would translate to other auth providers as well.&lt;/p&gt;

&lt;p&gt;The key to making this work is abstraction. Take any Firebase call that you'd normally make and hide it behind a function that may or may not do the same thing. Usually, it's the same sort of thing with some extras sprinkled in.&lt;/p&gt;

&lt;p&gt;In this case, we'll be looking at the &lt;code&gt;firebase.initializeApp&lt;/code&gt; function. In the normal production environment, this is super simple. We pass in a &lt;code&gt;siteConfig&lt;/code&gt; object and we're on our merry way. However, when working locally and/or with Firebase Emulators, this doesn't work one-for-one. In &lt;a href="https://firebase.google.com/docs/rules/unit-tests"&gt;the docs&lt;/a&gt;, they indicate that we should use &lt;code&gt;initializeTestApp&lt;/code&gt; instead to perform our initialization. This comes from the &lt;code&gt;@firebase/testing&lt;/code&gt; module as opposed to the &lt;code&gt;firebase/app&lt;/code&gt; module. This might seem perfect on the surface, but the issue is that anywhere we might normally use &lt;code&gt;firebase.&amp;lt;sometThing&amp;gt;&lt;/code&gt; to interact with the default firebase app, we can't. We instead need to work with the app instance returned from the call to &lt;code&gt;firebase.initializeTestApp()&lt;/code&gt;. By extension, this means we should structure our code so that we're &lt;em&gt;always&lt;/em&gt; using &lt;code&gt;app.&amp;lt;someThing&amp;gt;&lt;/code&gt; in favor of &lt;code&gt;firebase.&amp;lt;someThing&amp;gt;&lt;/code&gt;, regardless of whether we're using &lt;code&gt;initializeApp&lt;/code&gt; or &lt;code&gt;initializeTestApp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Again, this doesn't seem too bad on the surface, but there's one more catch: In each case, the app instance (as provided by &lt;code&gt;initialize*App(siteConfig)&lt;/code&gt;) is slightly different. Namely, &lt;code&gt;app.auth()&lt;/code&gt; is not a thing for apps initialized via &lt;code&gt;initializeTestApp()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the crux of the auth emulation problem. And this is what we are going to solve. Let's take a look at some code.&lt;/p&gt;

&lt;p&gt;Here is a utility function to initialize either a test or production app and return it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;importFirebase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDevelopment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeTestApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// set up custom hooks for auth mocking&lt;/span&gt;
        &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__internal__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Set up the auth observer&lt;/span&gt;
        &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a lot going on here, so let's break it down line by line.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I went with &lt;code&gt;async&lt;/code&gt; here because, in a couple lines, you'll see some dynamic imports. More on that in a sec. The other important piece here is that this &lt;code&gt;createApp&lt;/code&gt; function takes an &lt;code&gt;onAuthStateChanged&lt;/code&gt; callback and not a &lt;code&gt;siteConfig&lt;/code&gt; object like &lt;code&gt;initializeApp&lt;/code&gt;. Since we control the module containing this abstraction function, we can put our &lt;code&gt;siteConfig&lt;/code&gt; object here too for easy access. I mean, you can put the &lt;code&gt;siteConfig&lt;/code&gt; wherever you want, but to me, it makes sense to have the same module own the config block and the utility functions since the goal is to drive all Firebase-related functions through this abstraction module.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;onAuthStateChanged&lt;/code&gt; callback will be called when—&lt;em&gt;you guessed it&lt;/em&gt;—the auth state changes. In the production case, we can simply set up an auth observer in the usual manner, but in the development case, it's a bit more interesting. More on that in a sec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;importFirebase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's another layer of abstraction. We want a reference to Firebase as a module, and more specifically we might want a reference to the "testing" version of Firebase, but we don't actually care how it is obtained. Dynamic imports are a huge help here. This is what the definition of &lt;code&gt;importFirebase&lt;/code&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;importFirebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDevelopment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@firebase/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase/database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's nothing too surprising here. We are either importing "test" Firebase from &lt;code&gt;@firebase/testing&lt;/code&gt; or we are importing "real" Firebase from &lt;code&gt;firebase/app&lt;/code&gt; along with our other Firebase dependencies. Dynamically importing "real" Firebase is a little more involved, but it's basically the traditional way of doing it converted to dynamic import-form.&lt;/p&gt;

&lt;p&gt;I feel like this is a good time to mention that the reason for using dynamic imports here is so that you only ever end up importing &lt;em&gt;either&lt;/em&gt; the test Firebase &lt;em&gt;or&lt;/em&gt; the production one, but never both. Dynamic imports give us that flexibility.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The astute reader might realize that even with dynamic imports, Webpack will still bundle both modules into the output since we don't know until runtime which type of environment we'll be in. While this is true, it can be avoided by splitting the vendor modules out as part of the build and filtering out one of the two Firebase chunks, depending on the build type.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Development Mode
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDevelopment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming this is a React app created via &lt;code&gt;create-react-app&lt;/code&gt;, we can calculate whether or not this is a development build by looking for &lt;code&gt;process.env.NODE_ENV === 'development'&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeTestApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to initialize the test app using the now-obtained Firebase module, providing it our &lt;code&gt;siteConfig&lt;/code&gt; as usual. There's a key piece that needs to exist in the &lt;code&gt;siteConfig&lt;/code&gt; for this to work though: An &lt;code&gt;auth&lt;/code&gt; block. Here's an example config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;siteConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;authDomain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;databaseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isDevelopment&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:9000?ns=...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://....firebaseio.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;databaseName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;storageBucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;....appspot.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messagingSenderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;measurementId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u111111&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u111111@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That auth block is the key because that means that we can "inject" a user/email into the app manually as we see fit. There's a caveat though... Since this isn't &lt;em&gt;real&lt;/em&gt; auth, we'll never get &lt;code&gt;onAuthStateChanged&lt;/code&gt; callbacks fired. We're going to need to do that ourselves. And the first step towards doing that is to store a reference to the provided callback in our test app for later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// set up custom hooks for auth mocking&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__internal__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Here I chose &lt;code&gt;__internal__&lt;/code&gt; as a namespace that I figured nobody would collide with, but this could just as easily have been any other unique key on the app object.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Production Mode
&lt;/h2&gt;

&lt;p&gt;The other case to consider here is the production case. Let's take a look at the &lt;code&gt;else&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Set up the auth observer&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is very similar to what happens in development except we end up importing "real" Firebase and setting up an actual auth observer with that callback we took in as an argument.&lt;/p&gt;

&lt;p&gt;All of this is to say that we can now call&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MyFirebaseUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to get back a firebase app that's ready to go with either emulated auth in development or real auth in production.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I recommend holding onto this app instance in your application state so that it can be provided to any abstraction functions that may depend on it, such as simulating a login in development mode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Simulating onAuthStateChanged
&lt;/h2&gt;

&lt;p&gt;For any function we have that would trigger a login (or logout), we can add in a separate development-only flow in which we manually fire an &lt;code&gt;onAuthStateChanged&lt;/code&gt; event. Looking at the &lt;a href="https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onauthstatechanged"&gt;docs&lt;/a&gt;, those events are either passed a user or &lt;code&gt;null&lt;/code&gt; depending on whether the user is logged in or not.&lt;/p&gt;

&lt;p&gt;If our production flow for logging in a user looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doGoogleLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onFailure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;importFirebase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GoogleAuthProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Show the actual login popup. Succeeding here will update the internally managed uid and&lt;/span&gt;
    &lt;span class="c1"&gt;// auth of the app, which allows subsequent database calls (and other stuff) to work.&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;signInWithPopup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onFailure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can add in a development flow, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doGoogleLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onFailure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDevelopment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// https://firebase.google.com/docs/reference/js/firebase.auth#usercredential&lt;/span&gt;
        &lt;span class="nx"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TEST_ID_AUTH_TOKEN&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="c1"&gt;// Fire a simulated onAuthStateChanged event, passing it the user from our siteConfig.auth block&lt;/span&gt;
        &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__internal__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onAuthStateChanged&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;getIdToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TEST_ID_AUTH_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// production flow&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it! A sorta-kinda way to emulate auth from within a Firebase-enabled app. Hopefully you find this useful. I've been successfully using this approach in my project to help with offline testing using Firebase emulators.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>firebase</category>
      <category>testing</category>
    </item>
    <item>
      <title>Use TypeScript Interfaces Instead of ESLint PropTypes Validation</title>
      <dc:creator>Harvtronix</dc:creator>
      <pubDate>Sat, 23 Oct 2021 17:04:40 +0000</pubDate>
      <link>https://dev.to/harvtronix/use-typescript-interfaces-instead-of-eslint-proptypes-validation-27ka</link>
      <guid>https://dev.to/harvtronix/use-typescript-interfaces-instead-of-eslint-proptypes-validation-27ka</guid>
      <description>&lt;p&gt;In my TypeScript experimentation, I encountered an ESLint error I couldn't seem to resolve. The error had to do with proptype validation failing in the presence of what I believed to be a sufficient TypeScript interface to cover the props used by the functional component. So like any curious coder, I went on a huge tangent of discovery to figure out what was &lt;em&gt;really&lt;/em&gt; happening and what I could do about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the ESLint issue for reference:&lt;/strong&gt; &lt;a href="https://github.com/yannickcr/ESLint-plugin-React/issues/2275"&gt;Props validation with TS StatelessComponent (SFC) type fails&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is mostly a restating of the info I dropped in that issue in case anyone hits the same problem and wants a bit more of a detailed explanation about what's happening.&lt;/p&gt;

&lt;p&gt;In a nutshell, the issue is the result of using &lt;code&gt;FC&amp;lt;MyProps&amp;gt;&lt;/code&gt; to define a functional component in the presence of the ESLint prop-types rule. Under these circumstances, ESLint's prop-types plugin requires you to provide prop type definitions for internal props such as "children", even though TypeScript already covers this with the &lt;code&gt;FC&lt;/code&gt; and &lt;code&gt;SFC&lt;/code&gt; types.&lt;/p&gt;

&lt;p&gt;If you're using exclusively React-TypeScript with strict type checking (no js mixed in), then &lt;strong&gt;&lt;em&gt;in my opinion&lt;/em&gt;&lt;/strong&gt; it is safe to disable the &lt;code&gt;React/prop-types&lt;/code&gt; ESLint rule and instead rely solely on strong "compile-time" type checking to prevent you from doing bad things.&lt;/p&gt;

&lt;p&gt;This does forego the runtime type checking mentioned above, but if your entire application is written in TypeScript, then you can't compile/deploy your app with type errors in it anyway, so the loss of runtime type checking has minimal impact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note: This applies to both arrow functional components and regular functional components.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you write a TypeScript component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;InputThing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll either get an &lt;strong&gt;info&lt;/strong&gt; message from the TypeScript compiler saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Parameter 'props' implicitly has an 'any' type, but a better type may be inferred from usage. ts(7044)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or an &lt;strong&gt;error&lt;/strong&gt; message saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Parameter 'props' implicitly has an 'any' type. ts(7006)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you get the first one, you should add &lt;code&gt;"noImplicitAny": true&lt;/code&gt; to your tsconfig.json file, otherwise you're not fully taking advantage of what TypeScript has to offer.&lt;/p&gt;

&lt;p&gt;Given that as the baseline, let's say you wanted to use the destructured props &lt;code&gt;children&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt;. You'd write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;InputThing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two errors this time. One for &lt;code&gt;value&lt;/code&gt; and one for &lt;code&gt;children&lt;/code&gt;. Both saying that they have implicit "any" types, which aren't allowed. So now it's time to add type checking into the mix via a TypeScript interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;InputThingProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;InputThing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InputThingProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more errors and now we've enforced specific property types everywhere that &lt;code&gt;InputThing&lt;/code&gt; is used. I'll note that these TypeScript types/interfaces can be arbitrarily complex, above and beyond that which you could get from &lt;code&gt;PropTypes&lt;/code&gt; alone. This works because the generic-typed &lt;code&gt;FC&amp;lt;&amp;gt;&lt;/code&gt; takes a props interface as its type. &lt;code&gt;FC&lt;/code&gt; (&lt;code&gt;FunctionComponent&lt;/code&gt;) is defined in the React source as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;propTypes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;WeakValidationMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;contextTypes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ValidationMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;defaultProps&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PropsWithChildren&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;children&lt;/code&gt; is allowable by default and becomes unioned with whatever props you provide. &lt;em&gt;Hey, look! PropTypes is in there too!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What if you try to use a non-existent prop?
&lt;/h2&gt;

&lt;p&gt;If you try to use a &lt;code&gt;foo&lt;/code&gt; prop on &lt;code&gt;InputThing&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InputThing&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'bar'&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get an error saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Property 'foo' does not exist on type 'IntrinsicAttributes &amp;amp; InputThingProps &amp;amp; { children?: ReactNode; }'  .ts(2322)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which means you now have a reliable, TypeScript-only mechanism to define your props and ensure you provide them 100% correctly across all of your components!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To me, this covers all of the PropTypes use cases &lt;em&gt;except&lt;/em&gt; for the runtime checking, but in my opinion, this provides little value in a pure TypeScript React application.&lt;/p&gt;

&lt;p&gt;I hope you found this semi-deep-dive helpful to explain the situation a bit more. It's easy to encounter a problem like this and turn away from PropTypes, TypeScript, or even worse: both. The goal of this post isn't to say that TypeScript interfaces are better than PropTypes, or vise versa. It's instead to let you know that whichever path you choose, you're covered!&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>eslint</category>
    </item>
  </channel>
</rss>
