Code Monkey home page Code Monkey logo

Comments (6)

fobdy avatar fobdy commented on June 8, 2024 2

The same for me.
I have random Type instantiation is excessively deep and possibly infinite. errors encountered after adding one extra provideFactory.

from typed-inject.

DmitriyNikolenko avatar DmitriyNikolenko commented on June 8, 2024 1

It was a disaster, I spent a lot of time understanding what was happening with VSCode and eventually, I found this issue.

I really like this library but my project got stuck when the number of provideClass came to 20. I really don't know what to do.

Are there any ways to resolve this issue? Or I should refactor the whole project using another library?(((

from typed-inject.

nicojs avatar nicojs commented on June 8, 2024

Would a non-chainable API help you here? I mean, don't you have dependencies that depend on each other?

I.e. would you expect something like this to work?

interface Foo {
  foo: string;
}
class Bar {
  static readonly inject = ['foo'] as const;
  constructor(foo: Foo){ }
}
rootInjector.provide({
   foo: { value: { foo: 'hello'} },
   bar: { clazz: Bar }
})

Because something like that might be impossible to get statically type-checked.

from typed-inject.

matteralus avatar matteralus commented on June 8, 2024

Thanks for the response @nicojs. I see what you are saying. I actually took a stab at this today except using a proxy so I could do stuff like container.dep instead of container.resolve("dep"). The most type safe I could get it is was where the inject tokens had to be part of the keys passed in, and that the factory func args had to at least be one of the resulting types of the factory functions (or static values). It would be great to somehow link the args names to a type. When I have more time I may dig deeper into how you were doing your typing to understand if this is possible but I've kind of got something that unblocks me and has "better than nothing" typing lol. Here is what I ended up with if you are interested:

type AsContainerWithInstanceTypes<TIn extends Record<string, ((...args: any) => any) | { value: any }>> = {
  [prop in keyof TIn as prop]: TIn[prop] extends { value: any }
    ? TIn[prop]["value"]
    : TIn[prop] extends (...args: any) => any
    ? ReturnType<TIn[prop]>
    : unknown;
};

export function createDiContainer<
  T extends Record<
    string,
    | (((...args: AsContainerWithInstanceTypes<T>[keyof AsContainerWithInstanceTypes<T>][]) => any) & {
        inject?: readonly (keyof T)[];
      })
    | { value: any }
  >,
>(
  dependencies: T,
  options?: { logger?: Logger; onResolve?: (prop: string, val: any) => void },
): AsContainerWithInstanceTypes<T> {
  const _containerCache: Map<string, any> = new Map();
  const _onResolve = (prop: string, val: any) => {
    if (options?.onResolve) {
      options?.onResolve(prop, val);
    }
    _containerCache.set(prop, val);
    options?.logger?.debug(`returning ${prop} for first time`);
    return val;
  };

  const handler = {
    get: function (target: any, prop: string, receiver: any) {
      options?.logger?.debug(`resolving ${prop}`);
      if (_containerCache.has(prop)) {
        options?.logger?.debug(`returning ${prop} from cache`);
        return _containerCache.get(prop);
      }

      const targetDep = dependencies[prop];
      if (!targetDep) {
        throw new Error(`dependency "${prop}" not registered with container!`);
      }

      // TODO: implement classes. -mc
      if (!_.isFunction(targetDep)) {
        const resolved = targetDep.value;
        return _onResolve(prop, resolved);
      }

      const paramNames = (targetDep as any).inject || [];
      options?.logger?.debug(
        `${prop} has ${paramNames.length === 0 ? "no dependencies" : `dependencies: ${paramNames.join(", ")}`}`,
      );
      const params = paramNames.map((dep: string) => this.get(target, dep, receiver));
      const resolved = targetDep(...params);
      return _onResolve(prop, resolved);
    },
  };

  return new Proxy(dependencies, handler);
}

from typed-inject.

synkarius avatar synkarius commented on June 8, 2024

Chiming in to say that I got the same error as @fobdy on my 21st .provideXXXXXX.

from typed-inject.

nasuboots avatar nasuboots commented on June 8, 2024

The provideXxx method chains create heavily nested TChildContext.

image

So I patched to Injector type to flatten type as follows:

diff --git a/node_modules/typed-inject/dist/src/api/Injector.d.ts b/node_modules/typed-inject/dist/src/api/Injector.d.ts
index 9375bb6..49fed38 100644
--- a/node_modules/typed-inject/dist/src/api/Injector.d.ts
+++ b/node_modules/typed-inject/dist/src/api/Injector.d.ts
@@ -2,13 +2,14 @@ import { InjectableClass, InjectableFunction } from './Injectable';
 import { InjectionToken } from './InjectionToken';
 import { Scope } from './Scope';
 import { TChildContext } from './TChildContext';
 export interface Injector<TContext = {}> {
     injectClass<R, Tokens extends readonly InjectionToken<TContext>[]>(Class: InjectableClass<TContext, R, Tokens>): R;
     injectFunction<R, Tokens extends readonly InjectionToken<TContext>[]>(Class: InjectableFunction<TContext, R, Tokens>): R;
     resolve<Token extends keyof TContext>(token: Token): TContext[Token];
-    provideValue<Token extends string, R>(token: Token, value: R): Injector<TChildContext<TContext, R, Token>>;
-    provideClass<Token extends string, R, Tokens extends readonly InjectionToken<TContext>[]>(token: Token, Class: InjectableClass<TContext, R, Tokens>, scope?: Scope): Injector<TChildContext<TContext, R, Token>>;
-    provideFactory<Token extends string, R, Tokens extends readonly InjectionToken<TContext>[]>(token: Token, factory: InjectableFunction<TContext, R, Tokens>, scope?: Scope): Injector<TChildContext<TContext, R, Token>>;
+    provideValue<Token extends string, R>(token: Token extends keyof TContext ? never : Token, value: R): Injector<{ [K in keyof TContext]: TContext[K]} & { [T in Token]: R }>;
+    provideClass<Token extends string, R, Tokens extends readonly InjectionToken<TContext>[]>(token: Token extends keyof TContext ? never : Token, Class: InjectableClass<TContext, R, Tokens>, scope?: Scope): Injector<{ [K in keyof TContext]: TContext[K]} & { [T in Token]: R }>;
+    provideFactory<Token extends string, R, Tokens extends readonly InjectionToken<TContext>[]>(token: Token extends keyof TContext ? never : Token, factory: InjectableFunction<TContext, R, Tokens>, scope?: Scope): Injector<{ [K in keyof TContext]: TContext[K]} & { [T in Token]: R }>;
     dispose(): Promise<void>;
 }
 //# sourceMappingURL=Injector.d.ts.map
\ No newline at end of file
// argument  (to prevent from providing value with same token)
token: Token
// ↓
token: Token extends keyof TContext ? never : Token

// return type
Injector<TChildContext<TContext, R, Token>>
// ↓
Injector<{ [K in keyof TContext]: TContext[K]} & { [T in Token]: R }>;

https://github.com/nasuboots/typed-inject-types

Then I can chain the methods up to 49 without error. Also, it makes very faster to resolve type checking.

image

Over 49 method chains cause error: "Type instantiation is excessively deep and possibly infinite".
It looks like limitation of TypeScript.
microsoft/TypeScript#34933 (comment)

from typed-inject.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.