TypeScript CookBook

  • Classes and access levels
  • Properly type React Children

    In your functional component, use React.FC<Props> as function type and children will be implicitly accounted for in your Props, without needing to explicitly type them.

    import React, { ReactElement } from 'react';
    
    interface OwnProps {
      title: string
    }
    
    const Example: React.FC<OwnProps> = (props): ReactElement => {
      return (
        <div>
          <header>{props.title}</header>
    
          <main>
            {props.children}
          </main>
        </div>
      );
    }
    
    export default Example;
    

    Type a function in props

    interface OwnProps {
      // shorthand
      clickHandler(e: React.MouseEvent): void;
      
      // longhand
      changeHandler: (e: React.ChangeEvent) => void
    }
    

    Notice the shorthand notation.


    Type an event handler's event param

    interface OwnProps {
      clickHandler(e: React.MouseEvent): void;
    }
    
    const example: React.FC<OwnProps> = ({ clickHandler }): ReactElement => {
      function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
        clickHandler?.(e);
      }
    
      return <button onClick={handleClick}>Click</button>;
    };
    
    export default example;
    

    Don't use regular DOM events, but events under the React namespace, such as React.MouseEvent. Also provide an argument to the generic, specifying the type of element the handler is attached to.


    Type a ref

    const example: React.FC<OwnProps> = (): ReactElement => {
      const ref = useRef<HTMLDivElement>(null);
    
      return <div ref={ref} />;
    };
    

    Provide the type of the target element to the ref.


    Type a library which doesn't come with its own types

    In a type definition file (filename must follow the convention file.d.ts), write:

    declare module 'lib-name';
    

    This way TS will register the lib in the type system and (hopefully) turn off any errors.


    Type a class component

    
    interface props {}
    
    export default class Example extends Component<Props> { // ... }
    

    Null types

    Null types are automatically accounted for by TS in our type declarations (unless the strictNullChecks config option is active); null and undefined are assignable to every type.

    // TS sees: x: string | null | undefined
    var x: string = 'x';
    // no TS errors
    x = null;
    x = undefined;
    
    

    Create a class based on an interface

    interface Xyz {
      x: string;
    }
    
    class Example implements Xyz {
      x: string
    
      // ...
    }
    

    Classes and access levels

    • public: the default; access from the instance (dot notation from instantiated object) and from subclasses;
    • private: access restricted to the class scope; no access from the instance & neither from subclasses
    • protected: like private, but with access from subclasses
    • static: access directly from the class, without instantiating. (i.e. Math.PI)

    Access level | subclass access | instance access ---------------- | --------------------- | --------------------- private | X | X protected | √ | X static | √ | X public | √ | √

    Note: by setting a constructor as protected, we can prevent the class from being instanciated.


    Reference