I'm trying to roll my own dependency injection mechanism in TypeScript, and I've come across an interesting problem. When declaring my dependencies, I have to use named functions instead of arrow functions (which are my default typically), otherwise I get circular declaration errors.
Below are the set of types that make up my dependency resolver:
type CollectionTemplate = {
[key: string]: (...args: any) => any
}
type RegistryTemplate = {
[key: string]: CollectionTemplate
}
type RegistryCollection<R extends RegistryTemplate> = keyof R
type CollectionEntry<C extends CollectionTemplate> = keyof C
type BaseRegistry<R extends RegistryTemplate> = R
type BaseContext<R extends RegistryTemplate> = {
[C in RegistryCollection<R>]: {
[E in CollectionEntry<R[C]>]: ReturnType<R[C][E]>
}
}
type BaseUseDep<R extends RegistryTemplate> =
<C extends RegistryCollection<R>, E extends CollectionEntry<R[C]>>
(collection: C, entry: E) => BaseContext<R>[C][E]
Now, this all works fine when I use named functions:
type DepRegistry = BaseRegistry<typeof registry>
type DepContext = BaseContext<DepRegistry>
type UseDep = BaseUseDep<DepRegistry>
function greet(deps: UseDep)
{
return (name: string) =>
{
const console = deps('system', 'console')
console.log(name)
}
}
function printGreeting(deps: UseDep)
{
return () =>
{
const greet = deps('social', 'greet')
greet('John')
}
}
const registry = {
system: {
console: () => console,
},
social: {
greet,
printGreeting,
}
}
However, if I declare these functions with arrow functions instead of named functions, I get the following errors:
Type alias 'DepRegistry' circularly references itself. ts(2456)
Type alias 'UseDep' circularly references itself. ts(2456)
Why is this? Is it simply because I'm assigning a function to a variable instead of declaring an explicit function?
EDIT: Here are playgrounds with named functions and with arrow functions.