数组中带有点符号的TS严格路径
试图使MikroORM 中的populate参数对带有字符串路径的变体严格。我设法实现(更像是调整我在 TS discord 上找到的那个)根据我的需要工作的类型。当与单个参数一起使用时它可以正常工作,但是当与数组一起使用时,如果数组项之一有效,它将无法正确验证。AuthPath
所以问题是,我怎样才能让它与数组一起工作?甚至有可能吗?我试图使用元组类型来解决这个问题,但未能使其正常工作。我有点理解问题是共享泛型类型P- 我计划在返回类型中利用它,所以我需要一些东西来暴露从 params 到返回类型的签名中的实际(推断)类型。
完整的操场在这里。
下面是问题的演示:
declare const user: User;
declare function get1<O, P extends string>(obj: O, path: AutoPath<O, P>): void;
declare function get2<O, P extends string>(obj: O, path: AutoPath<O, P>[]): void;
// works fine with single item
get1(user, "friend.books.title")
get1(user, "friend.books.ref1.age")
get1(user, "friend.friend.name")
// @ts-expect-error
get1(user, "friend.friend.www")
// @ts-expect-error
get1(user, "friend.books.www")
// @ts-expect-error
get1(user, "friend.books.ref1.www")
// works fine with array when there is just one item
get2(user, ["friend.name"])
get2(user, ["friend.books.ref1.age"])
// @ts-expect-error
get2(user, ["friend.books.ref1.www"])
// if there are more items it works only sometimes
// @ts-expect-error
get2(user, ["friend.name", "books.author.www"])
// if we add one more item that is valid and on the root level, it will make it pass
get2(user, ["friend.name", "books.author.www", "age"])
这是AutoPath实体类型定义的代码:
class Collection<T> { items?: T[] }
class Reference<T> { item?: T }
type Book = {
id: string,
title: string,
author: User,
ref1: Reference<User>,
}
type User = {
id: string,
name: string,
age: number,
friend: User,
friends: Collection<User>,
books: Collection<Book>,
}
type ExtractType<T> = T extends Collection<infer U> ? U : (T extends Reference<infer U> ? U : T)
type StringKeys<T> = T extends Collection<any>
? `${Exclude<keyof ExtractType<T>, symbol>}`
: T extends Reference<any>
? `${Exclude<keyof ExtractType<T>, symbol>}`
: `${Exclude<keyof T, symbol>}`
type GetStringKey<T, K extends StringKeys<T>> = K extends keyof T ? ExtractType<T[K]> : never
type AutoPath<O, P extends string> =
(P & `${string}.` extends never ? P : P & `${string}.`) extends infer Q
? Q extends `${infer A}.${infer B}`
? A extends StringKeys<O>
? `${A}.${AutoPath<GetStringKey<O, A>, B>}`
: never
: Q extends StringKeys<O>
? (GetStringKey<O, Q> extends unknown ? Exclude<P, `${string}.`> : never) | (StringKeys<GetStringKey<O, Q>> extends never ? never : `${Q}.`)
: StringKeys<O>
: never
(该AutoPath类型仍然存在一些问题,但这并不重要 - 这个问题是关于如何将它与字符串数组而不是单个字符串参数一起使用)