hasDependency - greydragon888/real-router GitHub Wiki

getDependenciesApi().has

1. Overview

  • What it does: Checks if a dependency exists by name. Returns true if the dependency is registered, false if not.
  • When to use:
    • For checking dependency existence before use
    • For conditional logic based on dependency availability
    • For avoiding ReferenceError from getDependenciesApi().get()

2. Signature

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);
depsApi.has(name: keyof Dependencies): boolean

Usage Examples

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);

// Basic check
if (depsApi.has("analytics")) {
  const analytics = depsApi.get("analytics");
  analytics.trackEvent("Router started");
}

// Conditional initialization
if (!depsApi.has("cache")) {
  depsApi.set("cache", new CacheService());
}

// Feature detection
const features = {
  hasAnalytics: depsApi.has("analytics"),
  hasDevTools: depsApi.has("devTools"),
  hasCache: depsApi.has("cache"),
};

3. Parameters

name (required)

  • Type: keyof Dependencies
  • Purpose: Name of dependency to check
  • Allowed values: Any string (including empty, Unicode, emoji)
  • On error: TypeError if not a string

Behavior for Different Values

Value Result
Existing key true
Non-existing key false
Key with value 0 true
Key with value null true
Key with value false true
"" (empty string) Valid key
"用户" (Unicode) Valid key
"🚀" (emoji) Valid key
123 (number) TypeError
null TypeError
undefined TypeError

4. Return Value

  • Type: boolean
  • true: Dependency exists (including falsy values: 0, null, false)
  • false: Dependency is not registered

Important: Falsy Values

has() returns true for any registered value, including falsy:

const depsApi = getDependenciesApi(router);

depsApi.set("count", 0);
depsApi.set("disabled", false);
depsApi.set("empty", null);

depsApi.has("count"); // true (value is 0)
depsApi.has("disabled"); // true (value is false)
depsApi.has("empty"); // true (value is null)

5. Possible Errors

Condition Error Type Message
name not string TypeError [router.hasDependency]: dependency name must be a string, got {type}

Error Examples

const depsApi = getDependenciesApi(router);

// TypeError: not a string
depsApi.has(123);
// TypeError: [router.hasDependency]: dependency name must be a string, got number

depsApi.has(null);
// TypeError: [router.hasDependency]: dependency name must be a string, got object

depsApi.has(undefined);
// TypeError: [router.hasDependency]: dependency name must be a string, got undefined

6. Related Methods

Method When to use
getDependenciesApi().get Get dependency (throws ReferenceError if not found)
getDependenciesApi().set Set dependency
getDependenciesApi().remove Remove dependency
getDependenciesApi().getAll Get all dependencies
getDependenciesApi().reset Clear all dependencies

Comparison with get

const depsApi = getDependenciesApi(router);

// get — throws ReferenceError
try {
  const service = depsApi.get("maybeNotExist");
} catch (e) {
  // Handle error
}

// has — safe check
if (depsApi.has("maybeNotExist")) {
  const service = depsApi.get("maybeNotExist");
  // Guaranteed no error
}

7. Behavior

Main Scenarios

  • true for existing: Dependency is registered
  • false for non-existing: Dependency not found
  • true for falsy values: 0, null, false -- still exist
  • Read-only: Does not check disposed state
  • Works after dispose: Returns false since deps were cleared

Test Examples

const depsApi = getDependenciesApi(router);

// true if exists
expect(depsApi.has("foo")).toBe(true);

// false if doesn't exist
expect(depsApi.has("nonexistent")).toBe(false);

// false after removal
depsApi.remove("foo");
expect(depsApi.has("foo")).toBe(false);

Falsy Values

const depsApi = getDependenciesApi(router);

// 0 -- exists
depsApi.set("foo", 0);
expect(depsApi.has("foo")).toBe(true);

// null -- exists
depsApi.set("bar", null);
expect(depsApi.has("bar")).toBe(true);

// false -- exists
depsApi.set("foo", false);
expect(depsApi.has("foo")).toBe(true);

Non-String Parameters

const depsApi = getDependenciesApi(router);

// Numbers throw TypeError
expect(() => depsApi.has(123)).toThrowError(TypeError);

// null throws TypeError
expect(() => depsApi.has(null)).toThrowError(TypeError);

// undefined throws TypeError
expect(() => depsApi.has(undefined)).toThrowError(TypeError);

Case Sensitivity

const depsApi = getDependenciesApi(router);

depsApi.set("API", api1);
depsApi.set("api", api2);

expect(depsApi.has("API")).toBe(true);
expect(depsApi.has("api")).toBe(true);
expect(depsApi.has("Api")).toBe(false); // Case-sensitive

Empty String

const depsApi = getDependenciesApi(router);

expect(depsApi.has("")).toBe(false);

depsApi.set("", "empty-key-value");
expect(depsApi.has("")).toBe(true);

Integration with Other Methods

const depsApi = getDependenciesApi(router);

// With set
expect(depsApi.has("bar")).toBe(false);
depsApi.set("bar", "new value");
expect(depsApi.has("bar")).toBe(true);

// With reset
depsApi.setAll({ foo: 1, bar: "value" });
expect(depsApi.has("foo")).toBe(true);
expect(depsApi.has("bar")).toBe(true);

depsApi.reset();
expect(depsApi.has("foo")).toBe(false);
expect(depsApi.has("bar")).toBe(false);

After Dispose

router.dispose();
const depsApi = getDependenciesApi(router);

// Read-only methods still work after dispose
expect(depsApi.has("foo")).toBe(false); // false since deps were cleared
expect(depsApi.getAll()).toStrictEqual({});

Unicode and Special Characters

const depsApi = getDependenciesApi(router);

depsApi.set("api:v2", "value");
expect(depsApi.has("api:v2")).toBe(true);

depsApi.set("用户", "user");
expect(depsApi.has("用户")).toBe(true);

depsApi.set("🚀", "rocket");
expect(depsApi.has("🚀")).toBe(true);

Edge Cases

  • Empty string "": Valid key
  • Unicode and emoji: Supported
  • Special characters: "api:v2", "key.with.dots" -- work fine
  • Case-sensitive: "API" != "api"
  • Non-strings: TypeError (no type coercion)
  • Falsy values: 0, null, false -- return true

Guarantees

  • Always returns boolean
  • Throws TypeError for non-string names
  • Works with falsy values (0, null, false)
  • Case-sensitive checking
  • Unicode, emoji, special characters support
  • Uses Object.hasOwn() for prototype pollution protection
  • Works after dispose (returns false)

8. Migration

Old API (removed)

router.hasDependency(name);

New API

import { getDependenciesApi } from "@real-router/core/api";

const depsApi = getDependenciesApi(router);
depsApi.has(name);

Migration Examples

// Old
if (router.hasDependency("analytics")) {
  const analytics = router.getDependency("analytics");
  analytics.trackEvent("started");
}

// New
const depsApi = getDependenciesApi(router);
if (depsApi.has("analytics")) {
  const analytics = depsApi.get("analytics");
  analytics.trackEvent("started");
}
Aspect Old (router.hasDependency) New (getDependenciesApi(router).has)
Import None (method on router) import { getDependenciesApi }
Tree-shaking Always included Tree-shakeable
API style Facade method Standalone function
Behavior Identical Identical