Skip to content

Commit

Permalink
feat: trpc plugin, generate client helpers to provide prisima-like ty…
Browse files Browse the repository at this point in the history
…ping (zenstackhq#510)
  • Loading branch information
ymc9 authored Jun 24, 2023
1 parent 4b389fb commit c41980d
Show file tree
Hide file tree
Showing 9 changed files with 707 additions and 80 deletions.
4 changes: 2 additions & 2 deletions packages/plugins/tanstack-query/tests/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ ${sharedModel}
`,
true,
false,
[`${origDir}/dist`, 'svelte', '@types/react', '@tanstack/svelte-query'],
[`${origDir}/dist`, 'svelte@^3.0.0', '@types/react', '@tanstack/svelte-query'],
true
);
});
Expand All @@ -109,7 +109,7 @@ ${sharedModel}
`,
true,
false,
[`${origDir}/dist`, 'svelte', '@types/react', '@tanstack/svelte-query', 'superjson'],
[`${origDir}/dist`, 'svelte@^3.0.0', '@types/react', '@tanstack/svelte-query', 'superjson'],
true
);
});
Expand Down
7 changes: 6 additions & 1 deletion packages/plugins/trpc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"scripts": {
"clean": "rimraf dist",
"build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE dist",
"build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE 'res/**/*' dist",
"watch": "tsc --watch",
"lint": "eslint src --ext ts",
"prepublishOnly": "pnpm build",
Expand All @@ -32,15 +32,20 @@
"prettier": "^2.8.3",
"ts-morph": "^16.0.0",
"tslib": "^2.4.1",
"upper-case-first": "^2.0.2",
"zod": "3.21.1"
},
"devDependencies": {
"@trpc/next": "^10.32.0",
"@trpc/react-query": "^10.32.0",
"@trpc/server": "^10.32.0",
"@types/jest": "^29.5.0",
"@types/lower-case-first": "^1.0.1",
"@types/prettier": "^2.7.2",
"@zenstackhq/testtools": "workspace:*",
"copyfiles": "^2.4.1",
"jest": "^29.5.0",
"next": "^13.4.7",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.5",
"typescript": "^4.9.4"
Expand Down
17 changes: 17 additions & 0 deletions packages/plugins/trpc/res/client/next.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* eslint-disable */

import type { AnyRouter } from '@trpc/server';
import type { NextPageContext } from 'next';
import { type CreateTRPCNext, createTRPCNext as _createTRPCNext } from '@trpc/next';
import type { DeepOverrideAtPath } from './utils';
import type { ClientType } from '../routers';

export function createTRPCReact<
TRouter extends AnyRouter,
TPath extends string | undefined = undefined,
TSSRContext extends NextPageContext = NextPageContext,
TFlags = null
>(opts: Parameters<typeof _createTRPCNext>[0]) {
const r: CreateTRPCNext<TRouter, TSSRContext, TFlags> = _createTRPCNext<TRouter, TSSRContext, TFlags>(opts);
return r as DeepOverrideAtPath<CreateTRPCNext<TRouter, TSSRContext, TFlags>, ClientType<TRouter>, TPath>;
}
17 changes: 17 additions & 0 deletions packages/plugins/trpc/res/client/react.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* eslint-disable */

import type { AnyRouter } from '@trpc/server';
import type { CreateTRPCReactOptions } from '@trpc/react-query/shared';
import { type CreateTRPCReact, createTRPCReact as _createTRPCReact } from '@trpc/react-query';
import type { DeepOverrideAtPath } from './utils';
import type { ClientType } from '../routers';

export function createTRPCReact<
TRouter extends AnyRouter,
TPath extends string | undefined = undefined,
TSSRContext = unknown,
TFlags = null
>(opts?: CreateTRPCReactOptions<TRouter>) {
const r: CreateTRPCReact<TRouter, TSSRContext, TFlags> = _createTRPCReact<TRouter, TSSRContext, TFlags>(opts);
return r as DeepOverrideAtPath<CreateTRPCReact<TRouter, TSSRContext, TFlags>, ClientType<TRouter>, TPath>;
}
32 changes: 32 additions & 0 deletions packages/plugins/trpc/res/client/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable */

// inspired by: https://stackoverflow.com/questions/70632026/generic-to-recursively-modify-a-given-type-interface-in-typescript

type Primitive = string | Function | number | boolean | Symbol | undefined | null;

/**
* Recursively merges `T` and `R`. If there's a shared key, use `R`'s field type to overwrite `T`.
*/
export type DeepOverride<T, R> = T extends Primitive
? R
: R extends Primitive
? R
: {
[K in keyof T]: K extends keyof R ? DeepOverride<T[K], R[K]> : T[K];
} & {
[K in Exclude<keyof R, keyof T>]: R[K];
};

/**
* Traverse to `Path` (denoted by dot separated string literal type) in `T`, and starting from there,
* recursively merge with `R`.
*/
export type DeepOverrideAtPath<T, R, Path extends string | undefined = undefined> = Path extends undefined
? DeepOverride<T, R>
: Path extends `${infer P1}.${infer P2}`
? P1 extends keyof T
? Omit<T, P1> & Record<P1, DeepOverride<T[P1], DeepOverrideAtPath<T[P1], R, P2>>>
: never
: Path extends keyof T
? Omit<T, Path> & Record<Path, DeepOverride<T[Path], R>>
: never;
Loading

0 comments on commit c41980d

Please sign in to comment.