Skip to main content
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: David Colvin
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: David Colvin

Using Firebase 4 With TypeScript, Type Declarations, And npm

By
Published in Comments (2)

In the past, I've used Firebase with Angular; but, it was with Angular 1.x, which pre-dated the use of TypeScript. Now that I'm loving TypeScript (especially with Angular), I want to be able to use Firebase 4 with type-safety. Unfortunately, using type declarations with Firebase 4 was kind of confusing to me (and my unfrozen caveman lawyer brain). So, I thought I would put together a quick demo in case anyone else stumbled over this same use-case.

To be clear, Angular has an official wrapper around Firebase called AngularFire. But, Angular isn't the only place that TypeScript and Firebase can come together. You can use Firebase in any TypeScript application. As such, I wanted to get this demo working outside of Angular, in a stand-alone TypeScript application compiled with Webpack.

From what I've read, Firebase can use the "Definitely Typed" library to serve type definitions through "@types/firebase". However, if you're using npm to load Firebase (such as with a Webpack-based build process), you can use the type definitions that ship directly with the Firebase module.

The Firebase module doesn't export interfaces - it exports a single object that can be imported using the import-require syntax in TypeScript. Using this single object, you can then access the type definitions using a series of namespaces. For example, the imported "firebase" module gives you access to interfaces like:

  • firebase.app.App
  • firebase.database.Database
  • firebase.database.Reference
  • firebase.database.DataSnapshot
  • firebase.auth.Auth
  • firebase.User
  • firebase.messaging.Messaging

To these type definitions in action, I've created a simple TypeScript file that attempts to write-to and read-from a Firebase application:

// Import the core node modules.
import firebase = require( "firebase/app" );

// Import the other firebase modules for their SIDE-EFFECTS! These imports will augment
// the App module and provide the type-definition for the .database() method.
import "firebase/database";

// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //

// Initialize the Firebase application.
// --
// NOTE: Obviously, I'm obfuscating my app credentials here.
var app: firebase.app.App = firebase.initializeApp({
	apiKey: "****************",
	authDomain: "****************",
	databaseURL: "****************",
	projectId: "i****************",
	storageBucket: "****************",
	messagingSenderId: "****************"
});

// Access the real-time database in the initialized application.
var db: firebase.database.Database = app.database();

// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //

// Try to write to and read back from Firebase.
(async function test() {

	try {

		var bennadel: firebase.database.Reference = db.ref( "testing/ben-nadel" );

		await bennadel.set({
			name: "Ben Nadel",
			passions: [ "JavaScript", "TypeScript", "Angular", "ColdFusion", "UX" ]
		});

		var bennadelSnapshot: firebase.database.DataSnapshot = await bennadel.once( "value" );

		console.log( "Firebase Ref Value:" );
		console.dir( bennadelSnapshot.val() );

	} catch ( error ) {

		console.log( "Error!" );
		console.log( error );

	}

})();

As you can see, each of my variables is being declared with a type definition that is provided by the firebase module. The namespacing makes the declarations fairly verbose, which is why it might be wise to wrap your Firebase implementation in a Gateway / Repository class that can provide easier type inference. That said, when we compile this with Webpack and run it in the browser, we get the following page output:

Using Firebase 4 with TypeScript, npm, and Webpack.

As you can see, we were able to write to and read from the real-time Firebase database (also confirmed in the Firebase console, not shown). And, if we look at the Webpack / TypeScript build process, we can see that no errors were reported:

Firebase 4 being compiled with TypeScript and type declarations.

It took me over an hour to figure out how to get the type declarations working with Firebase in TypeScript. Maybe there was a simple ReadMe file that I was missing somewhere? No sure. But, if not, hopefully this will help anyone else who might be confused on where to find those interfaces and how to get them in your TypeScript logic.

Want to use code from this post? Check out the license.

Reader Comments

15,841 Comments

@All,

So, it looks like I don't actually need to include the "database" script for its side-effects:

> import "firebase/database";

Matt Ferderer corrected me on this. I think the issue I was having is that it was erroring-out when I was trying to use the "Definitely Typed" libraries (which were not compatible with the latest version of Firebase). When I switched over to trying to use the Type definitions that ship with the Firebase module, I forgot (it didn't occur to me) to try compiling it without the added "import".

But, I can confirm (at least locally), that it all still compiles if I remove the import.

15,841 Comments

@All,

An update on the snippet:

> import "firebase/database";

... it turns out, this IS needed; only, it's not needed for the type safety, it's needed for the side-effects. Meaning, without the import, the code will compile; but, if you try to run it in the browser, it will complain that .database() is not a runtime method.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel