The reason is that a project uses the Compiler API that comes with Typescript to generate the corresponding code, and appears when
Invalid arguments.[email protected]
> [email protected]
is upgraded. createInterfaceDeclaration
TypeError: Invalid arguments at Object.createInterfaceDeclaration (...\ ode_modules\.pnpm\[email protected]\ ode_modules\typescript\lib\typescript.js:172145:19) at makeInterfaceDeclaration (...\src\helper\compiler\helper\ts-interface.ts:46:36) at ...\src\helper\compiler\ts-typings.ts:30:89 at Array. map (<anonymous>) at createTSTypingsDeclaration (...\src\helper\compiler\ts-typings.ts:30:29) at tsCompiler (...\src\helper\compiler\index.ts:37:69) at ...\src\index.ts:52:52 at ...\ ode_modules\.pnpm\[email protected]\ ode_modules\p-pipe\index.js:12:25 at async Promise. all (index 0) at async openAPIWebClientGenerator (...\src\index.ts:59:3) at async actionApiGenerator (...\src\bin\action.ts:54:3)
Troubleshooting
Due to the large difference in the upgraded version, it took a lot of time to troubleshoot errors. The actual specific reason is that Typescript started strong parameter verification due to the abandonment of the decorators
parameter.
And factory.createInterfaceDeclaration
is also in it, starting at line 173993 of typescript.js
:
factory.createInterfaceDeclaration = ts.buildOverload("createInterfaceDeclaration") .overload({<!-- --> 0: function (modifiers, name, typeParameters, heritageClauses, members) {<!-- --> return createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members); }, 1: function (_decorators, modifiers, name, typeParameters, heritageClauses, members) {<!-- --> return createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members); }, }) .bind({<!-- --> // Validation corresponding to the current version 0: function (_a) {<!-- --> var modifiers = _a[0], name = _a[1], typeParameters = _a[2], heritageClauses = _a[3], members = _a[4], other = _a[5]; return (other === undefined) & amp; & amp; (modifiers === undefined || ts.every(modifiers, ts.isModifier)) & amp; & amp; (name === undefined || !ts.isArray(name)) & amp; & amp; (typeParameters === undefined || ts.isArray(typeParameters)) & amp; & amp; (heritageClauses === undefined || ts.every(heritageClauses, ts.isHeritageClause)) & amp; & amp; (members === undefined || ts.every(members, ts.isTypeElement)); }, // Validation corresponding to the old version 1: function (_a) {<!-- --> var decorators = _a[0], modifiers = _a[1], name = _a[2], typeParameters = _a[3], heritageClauses = _a[4], members = _a[5]; return (decorators === undefined || ts.every(decorators, ts.isDecorator)) & amp; & amp; (modifiers === undefined || ts.isArray(modifiers)) & amp; & amp; (name === undefined || !ts.isArray(name)) & amp; & amp; (typeParameters === undefined || ts.every(typeParameters, ts.isTypeParameterDeclaration)) & amp; & amp; (heritageClauses === undefined || ts.every(heritageClauses, ts.isHeritageClause)) & amp; & amp; (members === undefined || ts.every(members, ts.isTypeElement)); }, }) // Corresponding to the old version verification injection obsolete information .deprecate({<!-- --> 1: DISALLOW_DECORATORS }) .finish();
You can see that createInterfaceDeclaration
is now built by ts.buildOverload
. After buildOverload
is built, the API has a strong authentication type. If the incoming parameters are incorrect, it will will throw an error.
Part of the source code:
export function createOverload<T extends OverloadDefinitions>(name: string, overloads: T, binder: OverloadBinders<T>, deprecations?: OverloadDeprecations<T>) {<!-- --> Object.defineProperty(call, "name", {<!-- --> ...Object.getOwnPropertyDescriptor(call, "name"), value: name }); if (deprecations) {<!-- --> for (const key of Object. keys(deprecations)) {<!-- --> const index = + key as (keyof T & number); if (!isNaN(index) & amp; & amp; hasProperty(overloads, `${<!-- -->index}`)) {<!-- --> overloads[index] = deprecate(overloads[index], {<!-- --> ...deprecations[index], name }); } } } // The binder here can be seen as a validator const bind = createBinder(overloads, binder); return call as OverloadFunction<T>; function call(...args: OverloadParameters<T>) {<!-- --> const index = bind(args); const fn = index !== undefined ? overloads[index] : undefined; if (typeof fn === "function") {<!-- --> return fn(...args); } // Failure to pass validation throws an exception Invalid arguments throw new TypeError("Invalid arguments"); } } function createBinder<T extends OverloadDefinitions>(overloads: T, binder: OverloadBinders<T>): OverloadBinder<T> {<!-- --> return args => {<!-- --> for (let i = 0; hasProperty(overloads, `${<!-- -->i}`) & amp; & amp; hasProperty(binder, `${<!-- -->i}`); i + + ) {<!-- --> const fn = binder[i]; // Determine whether the verification is passed if (fn(args)) {<!-- --> return i as OverloadKeys<T>; } } }; } export function buildOverload(name: string): OverloadBuilder {<!-- --> return {<!-- --> overload: overloads => ({<!-- --> bind: binder => ({<!-- --> finish: () => createOverload(name, overloads, binder), deprecate: deprecations => ({<!-- --> finish: () => createOverload(name, overloads, binder, deprecations) }) }) }) }; }
Reason of the problem
Since the Typescript Compiler API does not support adding Comments to the properties of the Interface, the previous solution was to insert Comments above the properties when creating the Interface.
// export identifier const exportModifier = factory.createModifier(ts.SyntaxKind.ExportKeyword) // method name const interfaceName = factory. createIdentifier('MyInterface') return factory.createInterfaceDeclaration( [exportModifier], interfaceName, undefined, undefined, // The parameter definition here can only be inserted into TypeElement, and there is no strong verification before that can pass [ // multi-line comment factory.createJSDocComment( ['1', '2', '3'].join('\ '), [], ), // interface properties factory. createPropertySignature( //... ) // single line comment ts.addSyntheticLeadingComment( factory. createIdentifier(''), ts.SyntaxKind.SingleLineCommentTrivia, `~~~`, false, ), // interface properties factory. createPropertySignature( //... ) ], )
Solution
Since the Typescript Compiler API does not support the access of annotations, if this method cannot be used, adding annotations will become very troublesome. The actual reason is that the logic of buildOverload
is entered after passing in.
// verified the members of createInterfaceDeclaration members === undefined || ts.every(members, ts.isTypeElement)
Therefore, this method cannot pass the parameter verification. At present, there is no particularly good method to directly repair the source code of createInterfaceDeclaration
, but we can make magic changes to the method of isTypeElement
, so as to cheat the parameter verification of createInterfaceDeclaration
.
const isTypeElement = ts.isTypeElement ts.isTypeElement = function(node): node is ts.TypeElement {<!-- --> return isTypeElement(node) || ts.isJSDoc(node) || ts.isIdentifier(node) }