Skip to content

Instantly share code, notes, and snippets.

@joemaffei
Created March 20, 2024 01:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joemaffei/fec921db12f5a311eea94a2b2d007c9f to your computer and use it in GitHub Desktop.
Save joemaffei/fec921db12f5a311eea94a2b2d007c9f to your computer and use it in GitHub Desktop.
Stupid simple dependency injection for TypeScript
/**
* Module-level variable where all of the global dependency injection
* overrides are stored.
*/
const provisions = new Map<unknown, unknown>();
/**
* Adds an override to the global dependency injection context.
* TypeScript ensures that the signature of the override is the same
* as that of the dependency being overridden.
*
* There are probably dozens of TypeScript caveats to account for,
* but this is just to illustrate that it can be done easily.
*
* This is similar to Angular's `@Injectable({ providedIn: 'root' })`.
* @see https://angular.io/guide/providers
*/
export function provide<T>(token: T, override: T) {
provisions.set(token, override);
}
/**
* Returns the provided dependency for the respective token, if provided.
* If not, it returns the dependency itself.
* This is very similar to how Angular's inject function works.
* @see https://angular.io/api/core/inject
*/
export function inject<T>(token: T) {
return provisions.has(token) ? (provisions.get(token) as T) : token;
}
@joemaffei
Copy link
Author

import { useEffect, useState } from 'react';
import { provide, inject } from './dependency-injection';

// USE CASE 1: OVERRIDING GLOBALS FOR TESTING

function Component() {
  const fetch = inject(window.fetch);

  const [word, setWord] = useState('');

  useEffect(() => {
    (async () => {
      const response = await fetch(
        'https://random-word-api.herokuapp.com/word'
      );
      const text = (await response.json()) as [string];
      setWord(text[0]);
    })();
  }, []);
  return <div>{word}</div>;
}

function mockFetch() {
  return {
    json: async () => {
      return ['supercalifragilisticexpialidocious'];
    },
  };
}

export default function App2() {
  // provide(window.fetch, mockFetch); // in a test, you would put this in a beforeAll or beforeEach
  return <Component />;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment