问题是让编译器为此推断正确的类型container:
let container = Container({
"cache": async c => new UserCache(),
"user-service": async c => new UserService(await c("cache"))
});
但这取决于传递给 的参数的类型Container,这是一个对象文字,因此编译器会查看属性初始值设定项的类型:
async c => new UserCache()
并且看到它c没有类型注释,因此必须推断它的类型,并且约束是它与container- 哎呀,TypeScript 没有很好地使用循环约束进行类型推断。
c被推断为any,没有办法解决它:
// let's start with imaginary type P which maps names to provided types
// and declare desired container type
type ContainerFunc<P> = <N extends keyof P>(n: N) => Promise<P[N]>;
// and its argument type
type ProviderType<P> = { [N in keyof P]: (c: ContainerFunc<P>) => Promise<P[N]> };
function Container<P>(provider: ProviderType<P>): ContainerFunc<P> {
const cache: { [N in keyof P]?: Promise<P[N]> } = {};
const container = function<N extends keyof P>(name: N): Promise<P[N]> {
if (!cache[name]) {
cache[name] = provider[name](container);
}
return cache[name];
}
return container;
}
class UserCache { cache: {} }
class UserService {
constructor(private cache: UserCache) { }
}
let container = Container({
"cache": async c => new UserCache(),
"user-service": async c => new UserService(await c("cache"))
});
要删除循环,您必须删除c参数 - 它始终是container它本身,让我们这样使用它:
type ContainerFunc<P> = <N extends keyof P>(n: N) => Promise<P[N]>;
type ProviderType<P> = { [N in keyof P]: () => Promise<P[N]> };
function Container<P>(provider: ProviderType<P>): ContainerFunc<P> {
const cache: { [N in keyof P]?: Promise<P[N]> } = {};
const container = function<N extends keyof P>(name: N): Promise<P[N]> {
if (!cache[name]) {
cache[name] = provider[name]();
}
return cache[name];
}
return container;
}
class UserCache { cache: {} }
class UserService {
constructor(private cache: UserCache) { }
}
let container = Container({
"cache": async () => new UserCache(),
"user-service": async () => new UserService(await container("cache"))
});
但是现在container类型被推断为any,因为初始化器 for在函数体中"user-service"引用container,这阻止了推断该函数的返回类型。
您必须添加返回类型注释:
let container = Container({
"cache": async () => new UserCache(),
"user-service": async (): Promise<UserService> => new UserService(await container("cache"))
});
现在它正在工作:
let container = Container({
"cache": async () => new UserCache(),
"user-service": async (): Promise<UserService> => new UserService(await container("user-service"))
});
// error: Argument of type 'UserService' is not assignable to parameter of type 'UserCache'.
我相信这是你能得到的最好的。
正如您在评论中建议的那样更新,避免循环的另一种方法是在实施之前提前拼出所有提供者名称和提供的类型:
type ContainerFunc<P> = <N extends keyof P>(n: N) => Promise<P[N]>;
type ProviderType<P> = { [N in keyof P]: (c: ContainerFunc<P>) => Promise<P[N]> };
function Container<P>(provider: ProviderType<P>): ContainerFunc<P> {
const cache: { [N in keyof P]?: Promise<P[N]> } = {};
const container = function<N extends keyof P>(name: N): Promise<P[N]> {
if (!cache[name]) {
cache[name] = provider[name](container);
}
return cache[name];
}
return container;
}
class UserCache { cache: {} }
class UserService {
constructor(private cache: UserCache) { }
}
interface ProviderTypes {
cache: UserCache;
"user-service": UserService;
}
let container = Container<ProviderTypes>({
"cache": async c => new UserCache(),
"user-service": async c => new UserService(await c("cache"))
});