col*_*lxi 1 type-inference typescript
我已经努力了好几天,试图完成一些 Typescript 正确的推理,以便对提供给我的一个类构造函数的数据结构实现类型验证。
本质上,我的构造函数接收一个包含对象列表的数组,其中每个对象都包含(某种)插件的声明和插件的“自定义配置”。
我需要 Typescript 来确保提供的customConfig
内容与 上的类型匹配defaultConfig
,但是,我没有运气,甚至没有接近它。
我所做的几次尝试变得非常混乱和无意义,所以我将附上一个简单的代码表示,我希望它有助于表达这个想法:
我希望有人能提供一些光明
type Entry = {
extension: {
defaultConfig: Record<PropertyKey, unknown>
install: any
uninstall: any
},
customConfig: Record<PropertyKey, unknown>
}
function initExtensions<I extends Entry[]>(a: I): void { /* ... */ }
initExtensions([
{
extension: {
defaultConfig: { foo: true },
install: () => {/* ... */ },
uninstall: () => {/* ... */ },
},
customConfig: { foo: true } // <-- SHOULD BE OK
},
{
extension: {
defaultConfig: { bar: 123 },
install: () => {/* ... */ },
uninstall: () => {/* ... */ },
},
customConfig: { bar: true } // <-- Should complain as should be a NUMBER
},
])
Run Code Online (Sandbox Code Playgroud)
我希望下面的解决方案几乎能满足您的需求。
// keeping defaultConfig and customConfig as seperate generics makes TS inference more granular
type EntryRaw<C extends {}, U extends {}> = {
extension: {
defaultConfig: C
install: any
uninstall: any
},
customConfig: U
}
// checks if configs are equal types wise
type ValidEntry<E extends EntryRaw<{}, {}>> = E extends EntryRaw<infer C, infer U> ? C extends U ? U extends C ? E : never : never : never
type ValidEntries<ES extends EntryRaw<{}, {}>[]> =
ES extends [] ? ES : // recursion condition
ES extends [infer E, ...infer R] ? // destruct
E extends EntryRaw<{}, {}> ? // auxiliary check to allow ValidEntry check
R extends EntryRaw<{}, {}>[] ? // auxiliary check to allow recursive 'call'
E extends ValidEntry<E> ?
[E, ...ValidEntries<R>] : // entry ok, recursive 'call'
// some hacky error reporting
[{ __INCOMPATABLE_CONFIG__: [E['extension']['defaultConfig'], 'vs', E['customConfig']] } & Omit<E, 'customConfig'>, ...ValidEntries<R>]
: never : never : never
// I have been not able to make TS happy with single array argument
function initExtensions<ES extends EntryRaw<{}, {}>[]>(...es: ValidEntries<ES>): void {
}
initExtensions(
{
extension: {
defaultConfig: { foo: true },
install: () => {/* ... */ },
uninstall: () => {/* ... */ },
},
customConfig: { foo: true } // <-- SHOULD BE OK
},
{
extension: {
defaultConfig: { bar: 123 },
install: () => {/* ... */ },
uninstall: () => {/* ... */ },
},
customConfig: { bar: true } // <-- Should complain as should be a NUMBER
},
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
441 次 |
最近记录: |