Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeInfo not known in SvelteKit project #187

Open
brooksvb opened this issue Dec 18, 2021 · 11 comments
Open

TypeInfo not known in SvelteKit project #187

brooksvb opened this issue Dec 18, 2021 · 11 comments
Assignees

Comments

@brooksvb
Copy link

brooksvb commented Dec 18, 2021

Describe the bug

When I try to resolve a service using the class I get the error Error: TypeInfo not known for "Service1"

To Reproduce

I tried making a minimal Typescript project to reproduce this (with just a main.ts, service1.ts, and service2.ts), however, the bug did not occur in that case. I tried to get a debugger connected, but unfortunately since the project is running in Vite I cannot do so properly because Vite is not producing sourcemaps yet (vitejs/vite#3928). I'm at a loss of how to further debug.

I started a fresh SvelteKit project and reproduced the structure of my working project as minimally as possible, and was able to trigger the bug in this configuration.

  1. npm init svelte@next reproduction && cd reproduction
  2. In the project creation wizard select options Skeleton Project, Typescript enabled, add ESLint, add Prettier
  3. npm i reflect-metadata tsyringe in the new project
  4. Add to tsconfig.json
		"experimentalDecorators": true,
		"emitDecoratorMetadata": true
  1. Add files src/hooks.ts, src/service/service1.ts, and src/service/service2.ts
  2. npm run dev and open webpage to trigger error
// src/hooks.ts
import 'reflect-metadata'
import type { Handle } from "@sveltejs/kit"
import { container } from "tsyringe"
import { Service1 } from "./service/service1"

// This function runs on every request
export const handle: Handle = async ({ request, resolve }) => {
	const service1 = container.resolve(Service1)
	console.debug(service1)
	return resolve(request)
}
// src/service/service1.ts
import { singleton } from "tsyringe";
import type { Service2 } from "./service2";

@singleton()
export class Service1 {
	constructor(private service2: Service2) {}
}
// src/service/service2.ts
import { singleton } from "tsyringe";

@singleton()
export class Service2 {
}

The following is the resulting error from trying to access the webpage:

Error: TypeInfo not known for "Service1"
    at InternalDependencyContainer.construct (/home/brooksvb/Projects/tsyringe-repro/test2/node_modules/tsyringe/dist/cjs/dependency-container.js:265:23)
    at InternalDependencyContainer.resolveRegistration (/home/brooksvb/Projects/tsyringe-repro/test2/node_modules/tsyringe/dist/cjs/dependency-container.js:156:51)
    at InternalDependencyContainer.resolve (/home/brooksvb/Projects/tsyringe-repro/test2/node_modules/tsyringe/dist/cjs/dependency-container.js:100:33)
    at Object.handle (/home/brooksvb/Projects/tsyringe-repro/test2/src/hooks.ts:7:36)
    at respond (file:///home/brooksvb/Projects/tsyringe-repro/test2/node_modules/@sveltejs/kit/dist/ssr.js:1696:30)
    at svelteKitMiddleware (file:///home/brooksvb/Projects/tsyringe-repro/test2/node_modules/@sveltejs/kit/dist/chunks/index.js:4558:28)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

Expected behavior

No error should occur and service should be resolved.

Version:
4.6.0

@brooksvb
Copy link
Author

brooksvb commented Dec 18, 2021

Removing the dependency of Service2 in Service1 removes the bug.

// src/service/service1.ts
import { singleton } from "tsyringe";
import type { Service2 } from "./service2";

@singleton()
export class Service1 {
	// Causes no error when commented
	// constructor(private service2: Service2) {}
}

@brooksvb brooksvb changed the title TypeInfo not known TypeInfo not known in SvelteKit project Dec 19, 2021
@brooksvb
Copy link
Author

brooksvb commented Dec 19, 2021

The registryMap in the container contains Service1, but not Service2 right before calling resolve().

InternalDependencyContainer {
  parent: undefined,
  _registry: Registry { _registryMap: Map(1) { [class Service1] => [Array] } },
  interceptors: Interceptors {
    preResolution: PreResolutionInterceptors { _registryMap: Map(0) {} },
    postResolution: PostResolutionInterceptors { _registryMap: Map(0) {} }
  }
}

If I import Service2 in hooks.ts without using it, Service2 is now present in the registryMap.

I also tried moving both services directly into hooks.ts, and the bug is still triggered:

import 'reflect-metadata'
import type { Handle } from "@sveltejs/kit"
import { container, singleton } from "tsyringe"

@singleton()
export class Service1 {
	constructor(private service2: Service2) {}
}
@singleton()
export class Service2 {}

export const handle: Handle = async ({ request, resolve }) => {
	console.debug(container)
	// I would like to print out the typeInfo Map from the container at this point, but I can't figure out how 
	const service1 = container.resolve(Service1)
	console.debug(service1)
	const response = resolve(request)
	return response
}

While I can't directly confirm because of being unable to use a debugger with SvelteKit and being unable figure out how to print typeInfo, I am reasonably confident that the error is thrown from the DependencyContainer.construct function because the typeInfo Map, for some reason, does not contain a Service1 entry at this point.

const paramInfo = typeInfo.get(ctor);
if (!paramInfo || paramInfo.length === 0) {
if (ctor.length === 0) {
return new ctor();
} else {
throw new Error(`TypeInfo not known for "${ctor.name}"`);
}
}
const params = paramInfo.map(this.resolveParams(context, ctor));
return new ctor(...params);
}

One of my suspicions for the cause of this bug is that Vite is not internally compiling the TypeScript with metadata for the constructor arguments. The supporting info I have for this is that the bug is not triggered when the constructor is commented out, and the following from the README:

If you're using Babel (e.g. using React Native), you will need to configure it to emit TypeScript metadata.

Vite does not use Babel internally; I think the equivalent would be its usage of esbuild. I've read a bit into the docs of Vite and esbuild, but can't find any particular configuration options that seem related as far as I can tell

@nosachamos
Copy link

I'm facing this issue with Create React App (both 4.x and 5.x). I have tried enabling the babel-plugin-transform-typescript-metadata using craco to override CRA configuration, but no luck. Still get the same issue.

Does anyone know how to get this working with create react app?

@savy-91
Copy link

savy-91 commented Mar 14, 2022

I am also facing this issue on a Vue3 app that uses Vite

@JPilson
Copy link

JPilson commented Apr 29, 2022

I am also facing this issue on a Vue3 app that uses Vite

Same, it has been 2 days now without solution.
Did you get any solution?

@brooksvb
Copy link
Author

I am also facing this issue on a Vue3 app that uses Vite

Same, it has been 2 days now without solution. Did you get any solution?

Waited 2 days? I wasted 3+ days trying to debug this as thoroughly as I could and provided as much info as possible, and the maintainers of the project have given me zero response all these months. 😓 Needless to say I've given up on using Tsyringe and unfortunately have not found an alternative I like.

@savy-91
Copy link

savy-91 commented Apr 30, 2022

The problem is the compiler used by Vite, it doesn't work with annotations.

Unless you change the underlying compiler of your project you are better off switching to an annotation-free dependency injection library like https://brandi.js.org/

@JPilson
Copy link

JPilson commented Apr 30, 2022

Lol
I

I am also facing this issue on a Vue3 app that uses Vite

Same, it has been 2 days now without solution. Did you get any solution?

Waited 2 days? I wasted 3+ days trying to debug this as thoroughly as I could and provided as much info as possible, and the maintainers of the project have given me zero response all these months. 😓 Needless to say I've given up on using Tsyringe and unfortunately have not found an alternative I like.

I gave up and started using inversify
It's working fine to me

@tomsjansons
Copy link

I've just encountered the same problem (or at least something very similar). After lots of debugging it seems that doing a type import (from your example) import type { Service2 } from "./service2"; will not work but doing import { Service2 } from "./service2"; will work. Note the removal of type in the import. I have no idea why that's the case

@goetzst
Copy link

goetzst commented May 3, 2024

I've been facing a similar issue.
The solution that helped in my case was to explicitly add a @inject(Service2) annotation in the constructor of Service1.
It seems that you need at least one inject annotation in the constructor for the type information to be correctly registered.

@brooksvb
Copy link
Author

brooksvb commented May 6, 2024

It seems Microsoft abandoned this repository and no one maintains it, so I gave up using it 3 years ago when I first encountered the issue. Good luck if you decide to use it.

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

No branches or pull requests

7 participants