Skip to content

Commit fbbd2b8

Browse files
committed
feat: use never instead of void when types are not relevant (empty responses or unspecified parameters)
1 parent 321eb4c commit fbbd2b8

File tree

1 file changed

+20
-25
lines changed

1 file changed

+20
-25
lines changed

lib/process-document.ts

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function createIntersection(...types: (string | undefined)[]) {
2525
return (
2626
(type1 && type2
2727
? Writers.intersectionType(type1, type2, ...typeX)
28-
: type1) || 'void'
28+
: type1) || 'never'
2929
);
3030
}
3131

@@ -38,10 +38,13 @@ function createUnion(...types: (string | undefined)[]) {
3838
return type1 && type2 ? Writers.unionType(type1, type2, ...typeX) : type1;
3939
}
4040

41-
function isVoidKeyword(type: TypeAliasDeclaration) {
42-
return type?.getTypeNode()?.getKindName() === 'VoidKeyword';
41+
42+
function isUnspecifiedKeyword(type: TypeAliasDeclaration) {
43+
return type?.getTypeNode()?.getKind() === SyntaxKind.NeverKeyword;
4344
}
4445

46+
const unspecifiedKeyword = 'never' as const;
47+
4548
export async function processOpenApiDocument(
4649
outputDir: string,
4750
schema: OpenAPIV3.Document,
@@ -71,7 +74,7 @@ export async function processOpenApiDocument(
7174
});
7275

7376
const outputTypes = new Set<
74-
InterfaceDeclaration | TypeAliasDeclaration | 'void'
77+
InterfaceDeclaration | TypeAliasDeclaration | typeof unspecifiedKeyword
7578
>();
7679

7780
const refs = await $RefParser.default.resolve(schema);
@@ -373,7 +376,7 @@ export async function processOpenApiDocument(
373376

374377
const inputBodyType = typesFile.addTypeAlias({
375378
name: pascalCase(`${classDeclaration.getName() || 'INVALID'}Body`),
376-
type: bodyType?.getName() || 'void', // createIntersection(bodyType?.getName(), queryType?.getName()),
379+
type: bodyType?.getName() || unspecifiedKeyword, // createIntersection(bodyType?.getName(), queryType?.getName()),
377380
isExported: true,
378381
});
379382

@@ -384,10 +387,10 @@ export async function processOpenApiDocument(
384387
classDeclaration
385388
.getExtends()
386389
?.addTypeArgument(
387-
isVoidKeyword(inputType) ? 'void' : inputType.getName(),
390+
isUnspecifiedKeyword(inputType) ? unspecifiedKeyword : inputType.getName(),
388391
);
389392

390-
if (!isVoidKeyword(inputType)) {
393+
if (!isUnspecifiedKeyword(inputType)) {
391394
ctor.addParameter({
392395
name: 'input',
393396
type: inputType.getName(),
@@ -423,16 +426,15 @@ export async function processOpenApiDocument(
423426
!operationObject.responses ||
424427
Object.keys(operationObject.responses).length === 0
425428
) {
426-
classDeclaration.getExtends()?.addTypeArgument('undefined');
427-
// outputTypes.add('void');
429+
classDeclaration.getExtends()?.addTypeArgument(unspecifiedKeyword);
428430
}
429431

430432
for (const [statusCode, response] of Object.entries(
431433
operationObject.responses,
432434
).filter(([s]) => s.startsWith('2'))) {
433435
// early out if response is 204
434436
if (statusCode === '204') {
435-
classDeclaration.getExtends()?.addTypeArgument('undefined');
437+
classDeclaration.getExtends()?.addTypeArgument(unspecifiedKeyword);
436438
break;
437439
}
438440

@@ -459,11 +461,6 @@ export async function processOpenApiDocument(
459461
if (outputRef) {
460462
const outputType = typesAndInterfaces.get(outputRef);
461463

462-
// const outputTypeAlias = `${
463-
// outputType?.getName() || 'void'
464-
// }Output`;
465-
// ensureImport(outputType, outputTypeAlias);
466-
467464
if (outputType) {
468465
outputTypes.add(outputType);
469466
ensureImport(outputType);
@@ -481,10 +478,8 @@ export async function processOpenApiDocument(
481478
// text: `{${retVal}} HTTP ${statusCode}`,
482479
// });
483480
} else {
484-
const retVal = 'void';
485-
481+
const retVal = unspecifiedKeyword;
486482
classDeclaration.getExtends()?.addTypeArgument(retVal);
487-
488483
outputTypes.add(retVal);
489484

490485
// jsdoc.addTag({
@@ -509,10 +504,10 @@ export async function processOpenApiDocument(
509504
.replaceAll(/{/g, '${')}\``;
510505

511506
const bodyName = 'body';
512-
const ctorArgName = ctor.getParameters()[0]?.getName() || 'never';
507+
const ctorArgName = ctor.getParameters()[0]?.getName() || unspecifiedKeyword;
513508
// const hasParams = paramsType && !isVoidKeyword(paramsType);
514-
const hasBody = !isVoidKeyword(inputBodyType);
515-
const hasQuery = queryType && !isVoidKeyword(queryType);
509+
const hasBody = !isUnspecifiedKeyword(inputBodyType);
510+
const hasQuery = queryType && !isUnspecifiedKeyword(queryType) && queryParameters.length > 0;
516511

517512
const queryParameterNames = queryParameters.map((q) => q.name);
518513

@@ -522,7 +517,7 @@ export async function processOpenApiDocument(
522517
];
523518

524519
ctor.addStatements([
525-
!isVoidKeyword(inputType)
520+
!isUnspecifiedKeyword(inputType)
526521
? {
527522
kind: StructureKind.VariableStatement,
528523
declarationKind: VariableDeclarationKind.Const,
@@ -619,7 +614,7 @@ export async function processOpenApiDocument(
619614
mainFile.addImportDeclaration({
620615
moduleSpecifier: typesModuleSpecifier,
621616
namedImports: namedImports
622-
.filter(<T>(t: T | 'void'): t is T => t !== 'void')
617+
.filter(<T>(t: T | 'never'): t is T => t !== 'never')
623618
.map((t) => ({
624619
name: t.getName(),
625620
}))
@@ -631,8 +626,8 @@ export async function processOpenApiDocument(
631626
const clientClassDeclaration = mainFile.addClass({
632627
name: pascalCase(schema.info.title, 'RestClient'),
633628
isExported: true,
634-
extends: `${serviceClientClassName}<${allInputs?.getName() || 'void'}, ${
635-
allOutputs?.getName() || 'void'
629+
extends: `${serviceClientClassName}<${allInputs?.getName() || 'never'}, ${
630+
allOutputs?.getName() || 'never'
636631
}>`,
637632
});
638633

0 commit comments

Comments
 (0)