Skip to content

Commit c0d60a0

Browse files
authored
fix: optimize generated trpc typing and fix "select" issue (#972)
1 parent ec85058 commit c0d60a0

File tree

33 files changed

+1923
-100
lines changed

33 files changed

+1923
-100
lines changed

.github/workflows/build-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131

3232
strategy:
3333
matrix:
34-
node-version: [18.x]
34+
node-version: [20.x]
3535
prisma-version: [v4, v5]
3636

3737
steps:

packages/plugins/swr/tests/swr.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ ${sharedModel}
5959
{
6060
provider: 'postgresql',
6161
pushDb: false,
62-
extraDependencies: [`${origDir}/dist`, '[email protected]', '@types/[email protected]', 'swr@^2'],
62+
extraDependencies: [
63+
`${path.join(__dirname, '../dist')}`,
64+
65+
66+
'swr@^2',
67+
],
6368
compile: true,
6469
}
6570
);

packages/plugins/trpc/src/generator.ts

Lines changed: 15 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ function createAppRouter(
9999
appRouter.addImportDeclarations([
100100
{
101101
namedImports: [
102+
'unsetMarker',
102103
'type AnyRouter',
103104
'type AnyRootConfig',
104105
'type CreateRouterInner',
@@ -111,15 +112,12 @@ function createAppRouter(
111112
moduleSpecifier: '@trpc/server',
112113
},
113114
{
114-
namedImports: ['type PrismaClient', 'type Prisma'],
115+
namedImports: ['type PrismaClient'],
115116
moduleSpecifier: prismaImport,
116117
},
117-
{ defaultImport: 'z', moduleSpecifier: 'zod', isTypeOnly: true },
118118
]);
119119

120120
appRouter.addStatements(`
121-
${/** to be used by the other routers without making a bigger commit */ ''}
122-
export { PrismaClient } from '${prismaImport}';
123121
124122
export type BaseConfig = AnyRootConfig;
125123
@@ -129,56 +127,11 @@ function createAppRouter(
129127
procedures: ProcRouterRecord
130128
) => CreateRouterInner<Config, ProcRouterRecord>;
131129
132-
${
133-
/** this is needed in order to prevent type errors between a procedure and a middleware-extended procedure */ ''
134-
}
135-
export type ProcBuilder<Config extends BaseConfig> = ProcedureBuilder<{
136-
_config: Config;
137-
_ctx_out: Config['$types']['ctx'];
138-
_input_in: any;
139-
_input_out: any;
140-
_output_in: any;
141-
_output_out: any;
142-
_meta: Config['$types']['meta'];
143-
}>;
144-
145-
type ExtractParamsFromProcBuilder<Builder extends ProcedureBuilder<any>> =
146-
Builder extends ProcedureBuilder<infer P> ? P : never;
147-
148-
type FromPromise<P extends Promise<any>> = P extends Promise<infer T>
149-
? T
150-
: never;
151-
152-
${/** workaround to avoid creating 'typeof unsetMarker & object' on the procedure output */ ''}
153-
type Join<A, B> = A extends symbol ? B : A & B;
154-
155-
${
156-
/** you can name it whatever you want, but this is to make sure that
157-
the types from the middleware and the procedure are correctly merged */ ''
158-
}
159-
export type ProcReturns<
160-
PType extends ProcedureType,
161-
PBuilder extends ProcBuilder<BaseConfig>,
162-
ZType extends z.ZodType,
163-
PPromise extends Prisma.PrismaPromise<any>
164-
> = Procedure<
165-
PType,
166-
ProcedureParams<
167-
ExtractParamsFromProcBuilder<PBuilder>["_config"],
168-
ExtractParamsFromProcBuilder<PBuilder>["_ctx_out"],
169-
Join<ExtractParamsFromProcBuilder<PBuilder>["_input_in"], z.infer<ZType>>,
170-
Join<ExtractParamsFromProcBuilder<PBuilder>["_input_out"], z.infer<ZType>>,
171-
Join<
172-
ExtractParamsFromProcBuilder<PBuilder>["_output_in"],
173-
FromPromise<PPromise>
174-
>,
175-
Join<
176-
ExtractParamsFromProcBuilder<PBuilder>["_output_out"],
177-
FromPromise<PPromise>
178-
>,
179-
ExtractParamsFromProcBuilder<PBuilder>["_meta"]
180-
>
181-
>;
130+
export type UnsetMarker = typeof unsetMarker;
131+
132+
export type ProcBuilder<Config extends BaseConfig> = ProcedureBuilder<
133+
ProcedureParams<Config, any, any, any, UnsetMarker, UnsetMarker, any>
134+
>;
182135
183136
export function db(ctx: any) {
184137
if (!ctx.prisma) {
@@ -193,10 +146,10 @@ function createAppRouter(
193146

194147
appRouter
195148
.addFunction({
196-
name: 'createRouter<Router extends RouterFactory<BaseConfig>, Proc extends ProcBuilder<BaseConfig>>',
149+
name: 'createRouter<Config extends BaseConfig>',
197150
parameters: [
198-
{ name: 'router', type: 'Router' },
199-
{ name: 'procedure', type: 'Proc' },
151+
{ name: 'router', type: 'RouterFactory<Config>' },
152+
{ name: 'procedure', type: 'ProcBuilder<Config>' },
200153
],
201154
isExported: true,
202155
})
@@ -225,9 +178,7 @@ function createAppRouter(
225178
moduleSpecifier: `./${model}.router`,
226179
});
227180

228-
writer.writeLine(
229-
`${lowerCaseFirst(model)}: create${model}Router<Router, Proc>(router, procedure),`
230-
);
181+
writer.writeLine(`${lowerCaseFirst(model)}: create${model}Router(router, procedure),`);
231182
}
232183
});
233184
writer.write(');');
@@ -299,14 +250,7 @@ function generateModelCreateRouter(
299250

300251
modelRouter.addImportDeclarations([
301252
{
302-
namedImports: [
303-
'type RouterFactory',
304-
'type ProcBuilder',
305-
'type BaseConfig',
306-
'type ProcReturns',
307-
'type PrismaClient',
308-
'db',
309-
],
253+
namedImports: ['type RouterFactory', 'type ProcBuilder', 'type BaseConfig', 'db'],
310254
moduleSpecifier: '.',
311255
},
312256
]);
@@ -318,10 +262,10 @@ function generateModelCreateRouter(
318262
}
319263

320264
const createRouterFunc = modelRouter.addFunction({
321-
name: 'createRouter<Router extends RouterFactory<BaseConfig>, Proc extends ProcBuilder<BaseConfig>>',
265+
name: 'createRouter<Config extends BaseConfig>',
322266
parameters: [
323-
{ name: 'router', type: 'Router' },
324-
{ name: 'procedure', type: 'Proc' },
267+
{ name: 'router', type: 'RouterFactory<Config>' },
268+
{ name: 'procedure', type: 'ProcBuilder<Config>' },
325269
],
326270
isExported: true,
327271
isDefaultExport: true,

packages/plugins/trpc/src/helpers.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,14 @@ export function generateProcedure(
2121
writer.write(`
2222
${opType}: procedure.input(${typeName}).query(({ctx, input}) => checkRead(db(ctx).${lowerCaseFirst(
2323
modelName
24-
)}.${prismaMethod}(input as any))) as ProcReturns<
25-
"query",
26-
Proc,
27-
(typeof $Schema.${upperCaseFirst(modelName)}InputSchema)["${opType.replace('OrThrow', '')}"],
28-
ReturnType<PrismaClient["${lowerCaseFirst(modelName)}"]["${opType}"]>
29-
>,
24+
)}.${prismaMethod}(input as any))),
3025
`);
3126
} else if (procType === 'mutation') {
3227
// the cast "as any" is to circumvent a TS compiler misfired error in certain cases
3328
writer.write(`
3429
${opType}: procedure.input(${typeName}).mutation(async ({ctx, input}) => checkMutate(db(ctx).${lowerCaseFirst(
3530
modelName
36-
)}.${prismaMethod}(input as any))) as ProcReturns<
37-
"mutation",
38-
Proc,
39-
(typeof $Schema.${upperCaseFirst(modelName)}InputSchema)["${opType.replace('OrThrow', '')}"],
40-
ReturnType<PrismaClient["${lowerCaseFirst(modelName)}"]["${opType}"]>
41-
>,
31+
)}.${prismaMethod}(input as any))),
4232
`);
4333
}
4434
}
@@ -203,18 +193,18 @@ export function generateRouterTyping(writer: CodeBlockWriter, opType: string, mo
203193
writer.block(() => {
204194
if (procType === 'query') {
205195
writer.writeLine(`
206-
useQuery: <T extends ${genericBase}>(
196+
useQuery: <T extends ${genericBase}, TData = ${resultType}>(
207197
input: ${argsType},
208-
opts?: UseTRPCQueryOptions<string, T, ${resultType}, ${resultType}, Error>
198+
opts?: UseTRPCQueryOptions<string, T, ${resultType}, TData, Error>
209199
) => UseTRPCQueryResult<
210-
${resultType},
200+
TData,
211201
${errorType}
212202
>;
213203
useInfiniteQuery: <T extends ${genericBase}>(
214204
input: Omit<${argsType}, 'cursor'>,
215205
opts?: UseTRPCInfiniteQueryOptions<string, T, ${resultType}, Error>
216206
) => UseTRPCInfiniteQueryResult<
217-
${resultType},
207+
${resultType},
218208
${errorType}
219209
>;
220210
`);
@@ -223,7 +213,7 @@ export function generateRouterTyping(writer: CodeBlockWriter, opType: string, mo
223213
useMutation: <T extends ${genericBase}>(opts?: UseTRPCMutationOptions<
224214
${genericBase},
225215
${errorType},
226-
Prisma.${upperCaseFirst(modelName)}GetPayload<null>,
216+
${resultType},
227217
Context
228218
>,) =>
229219
Omit<UseTRPCMutationResult<${resultType}, ${errorType}, ${argsType}, Context>, 'mutateAsync'> & {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/** @type {import("eslint").Linter.Config} */
2+
const config = {
3+
parser: "@typescript-eslint/parser",
4+
parserOptions: {
5+
project: true,
6+
},
7+
plugins: ["@typescript-eslint"],
8+
extends: [
9+
"next/core-web-vitals",
10+
"plugin:@typescript-eslint/recommended-type-checked",
11+
"plugin:@typescript-eslint/stylistic-type-checked",
12+
],
13+
rules: {
14+
// These opinionated rules are enabled in stylistic-type-checked above.
15+
// Feel free to reconfigure them to your own preference.
16+
"@typescript-eslint/array-type": "off",
17+
"@typescript-eslint/consistent-type-definitions": "off",
18+
19+
"@typescript-eslint/consistent-type-imports": [
20+
"warn",
21+
{
22+
prefer: "type-imports",
23+
fixStyle: "inline-type-imports",
24+
},
25+
],
26+
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
27+
"@typescript-eslint/require-await": "off",
28+
"@typescript-eslint/no-misused-promises": [
29+
"error",
30+
{
31+
checksVoidReturn: { attributes: false },
32+
},
33+
],
34+
},
35+
};
36+
37+
module.exports = config;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# database
12+
/prisma/db.sqlite
13+
/prisma/db.sqlite-journal
14+
15+
# next.js
16+
/.next/
17+
/out/
18+
next-env.d.ts
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# local env files
34+
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
35+
.env
36+
.env*.local
37+
38+
# vercel
39+
.vercel
40+
41+
# typescript
42+
*.tsbuildinfo
43+
package-lock.json
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Create T3 App
2+
3+
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.
4+
5+
## What's next? How do I make an app with this?
6+
7+
We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.
8+
9+
If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.
10+
11+
- [Next.js](https://nextjs.org)
12+
- [NextAuth.js](https://next-auth.js.org)
13+
- [Prisma](https://prisma.io)
14+
- [Tailwind CSS](https://tailwindcss.com)
15+
- [tRPC](https://trpc.io)
16+
17+
## Learn More
18+
19+
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
20+
21+
- [Documentation](https://create.t3.gg/)
22+
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials
23+
24+
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
25+
26+
## How do I deploy this?
27+
28+
Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
3+
* for Docker builds.
4+
*/
5+
await import("./src/env.js");
6+
7+
/** @type {import("next").NextConfig} */
8+
const config = {
9+
reactStrictMode: true,
10+
11+
/**
12+
* If you are using `appDir` then you must comment the below `i18n` config out.
13+
*
14+
* @see https://github.com/vercel/next.js/issues/41980
15+
*/
16+
i18n: {
17+
locales: ["en"],
18+
defaultLocale: "en",
19+
},
20+
};
21+
22+
export default config;

0 commit comments

Comments
 (0)