我的 AWS lambda 函数中使用了 x 个模块,例如
UserModule
、NotificationsModule
、CompanyModule
等。我创建了一个接口,描述模块的结构如下:
interface Modules {
company: ICompanyModule
user: {
base: IUserModule
}
notifications: {
settings: INotificationSettingsModule
details: INotificationDetailsModule
}
}
假设我需要在一个函数中使用公司和用户库模块,我必须手动导入并实例化它们。如果我只有少数几个功能就可以工作,但事实并非如此。为了减少导入和手动工作量,我认为我应该创建一个
factory
方法,该方法将返回一个仅包含该函数所需模块的对象。例如:
// Single module
const module = factory('company') // Type would be ICompanyModule
// Multiple Modules
const modules = factory(['company', 'user.base']) // Type would be { company: ICompanyModule, 'user.base': IUserModule }
工厂方法的输入将是
Modules
界面中的键数组。
我即将找到“解决方案”,但我似乎无法修复
Type instantiation is excessively deep and possibly infinite
错误。以下是我目前拥有的:
// This gets all the keys and nested keys of my Modules interface
type Path<T, Key extends keyof T = keyof T> = Key extends string
? T[Key] extends Record<string, unknown>
?
| `${Key}.${Path<T[Key], Exclude<keyof T[Key], keyof Array<unknown>>> & string}`
| `${Key}.${Exclude<keyof T[Key], keyof Array<unknown>> & string}`
| Key
: Key
: never
// This gets the value for the Path wether it be nested or not
type PathValue<T, P extends Path<T>> = P extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? Rest extends Path<T[Key]>
? PathValue<T[Key], Rest>
: never
: never
: P extends keyof T
? T[P]
: never
// This is my ReturnType that takes in the a single key or array of keys and builds the object type
type ReturnObject<T extends Object, P extends Path<T> | Array<Path<T>>> = P extends Array<Path<T>>
? {
[Key in P[number]]: Key extends keyof T
? T[Key] extends Object
? Key extends Path<T[Key]>
? ReturnObject<T[Key], Key>
: T[Key]
: never
: Key extends `${infer K}.${infer Rest}`
? K extends keyof T
? T[K] extends Object
? Rest extends Path<T[K]>
? ReturnObject<T[K], Rest>
: never
: never
: never
: never
}
: P extends keyof T
? T[P]
: P extends `${infer K}.${infer Rest}`
? K extends keyof T
? T[K] extends Object
? Rest extends Path<T[K]>
? ReturnObject<T[K], Rest>
: never
: T[K]
: never
: never
// This is the factory function declaration
declare function factory<T extends ModuleFactory, P extends Path<T> | Array<Path<T>>>(
modules: P
): ReturnObject<T, P>
现在可以了。当我使用任何给定的键创建调用
factory
时,我会得到正确的对象结构,但 Typescript 在 Type instantiation is excessively deep and possibly infinite
处的
ReturnType
中抛出
{ [Key in P[number]]: ... }
错误
经过几天的混乱,我最好的猜测是问题是 P 可以扩展数组
您可以使用不易出错的路径获取器
Get
来获取值和泛型类型验证器conforms
以仅允许正确的路径
type conforms<T, V> = T extends V ? T : V;
type validatePath<Path, Obj> =
| Path extends keyof Obj ? Path
: Path extends `${infer F extends keyof Obj & string}.${infer L}` ? `${F}.${validatePath<L, Obj[F]>}`
: keyof Obj & string
type Get<Obj, Path> =
| Path extends `${infer F}.${infer L}` ? Get<Get<Obj, F>, L>
: Path extends keyof Obj ? Obj[Path]
: [Obj, Path]
function factoryS<Path extends string>(path: conforms<Path, validatePath<Path, Modules>>): Get<Modules, Path> {
return null!;
}
function factoryA<const A>(list: conforms<A, { [K in keyof A]: validatePath<A[K], Modules> }>)
: A extends readonly string[] ? { [K in A[number]]: Get<Modules, K> } : never {
return null!;
}
// you may make them single function overloads