Improve path.get typings with TS template literal types (#13588)

This commit is contained in:
王清雨 2021-07-29 03:47:29 +08:00 committed by GitHub
parent 0a4b1b339c
commit d45ad500e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -320,6 +320,44 @@ export function getAllPrevSiblings(this: NodePath): NodePath[] {
return siblings; return siblings;
} }
// convert "1" to 1 (string index to number index)
type MaybeToIndex<T extends string> = T extends `${bigint}` ? number : T;
type Pattern<Obj extends string, Prop extends string> = `${Obj}.${Prop}`;
// split "body.body.1" to ["body", "body", 1]
type Split<P extends string> = P extends Pattern<infer O, infer U>
? [MaybeToIndex<O>, ...Split<U>]
: [MaybeToIndex<P>];
// get all K with Node[K] is t.Node | t.Node[]
type NodeKeyOf<Node extends t.Node | t.Node[]> = keyof Pick<
Node,
{
[Key in keyof Node]-?: Node[Key] extends t.Node | t.Node[] ? Key : never;
}[keyof Node]
>;
// traverse the Node with tuple path ["body", "body", 1]
// Path should be created with Split
type Trav<
Node extends t.Node | t.Node[],
Path extends unknown[],
> = Path extends [infer K, ...infer R]
? K extends NodeKeyOf<Node>
? R extends []
? Node[K]
: // @ts-expect-error ignore since TS is not smart enough
Trav<Node[K], R>
: never
: never;
type ToNodePath<T> = T extends Array<t.Node | null | undefined>
? Array<NodePath<T[number]>>
: T extends t.Node | null | undefined
? NodePath<T>
: never;
function get<T extends t.Node, K extends keyof T>( function get<T extends t.Node, K extends keyof T>(
this: NodePath<T>, this: NodePath<T>,
key: K, key: K,
@ -330,6 +368,12 @@ function get<T extends t.Node, K extends keyof T>(
? NodePath<T[K]> ? NodePath<T[K]>
: never; : never;
function get<T extends t.Node, K extends string>(
this: NodePath<T>,
key: K,
context?: boolean | TraversalContext,
): ToNodePath<Trav<T, Split<K>>>;
function get<T extends t.Node>( function get<T extends t.Node>(
this: NodePath<T>, this: NodePath<T>,
key: string, key: string,