{"record":{"id":"26d50af4f43a7495","repo":"pulumi/pulumi","slug":"component-componentname-constructor-args-pa","errorCode":null,"errorMessage":"Component '${componentName}' constructor 'args' parameter must have a type","messagePattern":"Component '(.+?)' constructor 'args' parameter must have a type","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"sdk/nodejs/provider/experimental/analyzer.ts","lineNumber":317,"sourceCode":"    private analyzeComponent(node: typescript.ClassDeclaration): ComponentDefinition {\n        const componentName = node.name?.text!;\n\n        // We expect exactly 1 constructor, and it must have and 'args'\n        // parameter that has an interface type.\n        const constructors = node.members.filter((member: typescript.ClassElement) =>\n            ts.isConstructorDeclaration(member),\n        ) as typescript.ConstructorDeclaration[];\n        if (constructors.length !== 1) {\n            throw new Error(`Component '${componentName}' must have exactly one constructor`);\n        }\n        const argsParam = constructors?.[0].parameters.find((param: typescript.ParameterDeclaration) => {\n            return ts.isIdentifier(param.name) && param.name.escapedText === \"args\";\n        });\n        if (!argsParam) {\n            throw new Error(`Component '${componentName}' constructor must have an 'args' parameter`);\n        }\n        if (!argsParam.type) {\n            throw new Error(`Component '${componentName}' constructor 'args' parameter must have a type`);\n        }\n        const args = this.checker.getTypeAtLocation(argsParam.type);\n        const argsSymbol = args.getSymbol();\n        if (!argsSymbol || !isInterface(argsSymbol)) {\n            throw new Error(`Component '${componentName}' constructor 'args' parameter must be an interface`);\n        }\n\n        let inputs: Record<string, PropertyDefinition> = {};\n        // Use args.getProperties() instead of argsSymbol.members to include\n        // properties inherited from extended interfaces.\n        const argsProperties = args.getProperties();\n        if (argsProperties.length > 0) {\n            inputs = this.analyzeSymbols(\n                { component: componentName, inputOutput: InputOutput.Neither, typeName: argsSymbol.getName() },\n                argsProperties,\n            );\n        }\n","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/sdk/nodejs/provider/experimental/analyzer.ts#L299-L335","documentation":"Beyond being named `args`, the parameter must carry an explicit type annotation so the analyzer can inspect the args interface via the TypeScript checker. An untyped (implicitly any) parameter gives the checker nothing to enumerate into schema properties.","triggerScenarios":"Declaring `constructor(args)` or `constructor(args: any)` with no concrete interface type annotation.","commonSituations":"Quick prototypes without typed args; implicit-any codebases without strict checking.","solutions":["Add an explicit interface type to the args parameter","Define the inputs as an exported interface (e.g. `interface MyComponentArgs {...}`) and annotate the parameter with it","Enable noImplicitAny to catch this at compile time"],"exampleFix":"// before\nconstructor(args) { ... }\n// after\nconstructor(args: MyComponentArgs) { ... }","handlingStrategy":"type-guard","validationCode":"function argsParamTyped(c: any): boolean { const m = c.toString().match(/constructor\\(\\s*args\\s*\\)\\s*{/); return !m; }","typeGuard":"function hasTypedArgs<T extends new (args: I) => any, I>(c: T): c is T { return true; }","tryCatchPattern":null,"preventionTips":["Enable noImplicitAny in tsconfig","Always annotate args with an interface type","Never use `any` for component args"],"tags":["nodejs","analyzer","typescript","typing"],"backgroundTag":"untyped-args-parameter","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}