TypeScript without TypeScript


Alternative title: Using TypeScript with Intellisense.

We're going to start off in this codeSandbox repository for the time being.

TypeScript Configuration

compilerOptions:

  • target: Specifies the ECMAScript target version for the compiled JavaScript. In this case, it's set to "es5," which means the generated JavaScript should be compatible with ECMAScript 5.

  • lib: Specifies a set of built-in TypeScript declaration files to include in the compilation. In this example, it includes declarations for the DOM, DOM Iterable, and ESNext.

  • allowJs: Allows the inclusion of JavaScript files in the TypeScript project.

  • skipLibCheck: Skips type checking of all the declaration files (.d.ts) in the project.

  • esModuleInterop: Enables compatibility with modules using CommonJS-style imports.

  • allowSyntheticDefaultImports: Allows default imports from modules with no default export.

  • strict: Enables all strict type-checking options. It's a shorthand for enabling a set of strict checks.

  • forceConsistentCasingInFileNames: Ensures that files included in the project have consistent casing of their names.

  • noFallthroughCasesInSwitch: Reports errors for fallthrough cases in switch statements.

  • module: Specifies the module system for the generated code. In this case, it's set to "esnext," indicating ECMAScript modules.

  • moduleResolution: Specifies how module names are resolved. It's set to "node," which means the Node.js module resolution strategy.

  • resolveJsonModule: Enables importing JSON files as modules.

  • isolatedModules: Disallows files from being transpiled separately. Each file is treated as a separate module.

  • noEmit: Prevents TypeScript from emitting output files (JavaScript files). This is useful when you only want to perform type-checking without generating the actual JavaScript code.

  • jsx: Specifies the JSX factory function to use when targeting React JSX emit. In this case, it's set to "react-jsx."

include:

  • Specifies the files or patterns to include in the compilation. In this case, it includes all files under the "src" directory.

Alright, let's start simple here and play a fun game: Is the component below written in JavaScript or TypeScript?

const NameBadge = () => {
  return (
    <section className="badge">
      <header className="badge-header">
        <h1 className="text-5xl">HELLO</h1>
        <p>My name is…</p>
      </header>
      <div className="badge-body">
        <p className="badge-name">Prashant Rawal</p>
      </div>
      <footer className="badge-footer" />
    </section>
  );
};

export default NameBadge;

The correct answer is "yes." If we're being pedantic, since the file ends in .tsx, it's technically TypeScript, but if I changed the file extension to .jsx, it would be perfectly fine. (Franky, other than all the className attributes, it could just be HTML with a little tweaking. There isn't really much going on with this component.)

This is one of the core principles that I want us to remember during our time together: Generally speaking, TypeScript tries its best to get our of your way. It will do it's best to figure out what's going on. You only need to step in when it can't figure it out on your behalf.

But, you will notice that Visual Studio Code's Intellisense is trying its best to figure out the types for you. If you hover over NameBadge, you'll see the following:

const NameBadge: () => JSX.Element;

This makes sense. Functions are valid React components these days and since we're returning JSX, it deduced that the return type of this function is a JSX.element.

For fun, let's add a simple little function at the bottom of the file just to confirm our suspicions.

const four = () => 2 + 2;

If you hover this function, you'll see:

const four: () => number;

We didn't have to give the function a return type. TypeScript figured it out. It analyzed the function and saw that there is only one kind of value that is ever coming out of the function—a number. So, it went ahead and typed it for us.

If we add some chaos to the equation, you'll see that TypeScript respects the confusion that you caused.

 const NameBadge = () => {
+  if (Math.round(Math.random())) return null;
   return (

Now, TypeScript tells us that this function will give us either a JSX.Element or it's going to give us null depending on which way the winds blow.

const NameBadge: () => JSX.Element | null;