Polkadot.js调用signAndSend传入signer参数触发编译错误
问题背景
- 开发环境为Next.js框架,基于Polkadot.js实现前端交互逻辑
- 实现目标:对接浏览器钱包扩展获取账户,调用
signAndSend方法发起已部署合约的交易 - 异常表现:代码编译阶段抛出TypeScript类型不匹配错误
业务代码片段
const injector = await web3FromSource(performingAccount.meta.source); const keyring = new Keyring({ type: 'sr25519' }); // const accountKeyring = keyring.addFromUri('//Alice'); const accountKeyring = keyring.addFromAddress(performingAccount.address); const flip = await contract.tx.flip({ value: 0, gasLimit: -1 }); flip.signAndSend(accountKeyring,{signer:injector.signer},(result) => { if (result.status.isInBlock) { setResult("in a block"); } else if (result.status.isFinalized) { setResult("finalized"); } });
编译报错信息
(property) signer?: Signer | undefined Type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/rpc-core/node_modules/@polkadot/types/types/extrinsic").Signer' is not assignable to type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/api-contract/node_modules/@polkadot/types/types/extrinsic").Signer'. Types of property 'update' are incompatible. Type '((id: number, status: H256 | ISubmittableResult) => void) | undefined' is not assignable to type '((id: number, status: ISubmittableResult | H256) => void) | undefined'. Type '(id: number, status: H256 | ISubmittableResult) => void' is not assignable to type '(id: number, status: ISubmittableResult | H256) => void'. Types of parameters 'status' and 'status' are incompatible. Type 'ISubmittableResult | H256' is not assignable to type 'H256 | ISubmittableResult'. Type 'ISubmittableResult' is not assignable to type 'H256 | ISubmittableResult'. Type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/api-contract/node_modules/@polkadot/types/types/extrinsic").ISubmittableResult' is not assignable to type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/rpc-core/node_modules/@polkadot/types/types/extrinsic").ISubmittableResult'. Types of property 'dispatchError' are incompatible. Type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/api-contract/node_modules/@polkadot/types/interfaces/system/types").DispatchError | undefined' is not assignable to type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/rpc-core/node_modules/@polkadot/types/interfaces/system/types").DispatchError | undefined'. Property '#private' is missing in type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/api-contract/node_modules/@polkadot/types/interfaces/system/types").DispatchError' but required in type 'import("/Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/@polkadot/rpc-core/node_modules/@polkadot/types/interfaces/system/types").DispatchError'.ts(2322) Enum.d.ts(27, 5): '#private' is declared here. submittable.d.ts(17, 5): The expected type comes from property 'signer' which is declared here on type 'Partial<SignerOptions>'
错误产生原因
- 核心原因:Polkadot生态依赖版本不一致,存在多份类型副本
从报错路径可以看出,项目中@polkadot/rpc-core和@polkadot/api-contract两个包各自在自身的node_modules目录下嵌套依赖了不同版本的@polkadot/types包。TypeScript会将不同文件路径下的同名类型判定为完全独立、不兼容的类型,哪怕两个类型的结构逻辑完全一致;报错中提到的#private私有属性缺失,就是不同版本的DispatchError类定义存在差异导致的典型表现。 - 代码写法存在逻辑问题
对接浏览器钱包扩展签名的场景下,签名动作由钱包侧完成,不需要本地通过Keyring构造密钥对实例。通过keyring.addFromAddress生成的密钥对不包含私钥,本身也无法完成本地签名操作。
修复方案
- 统一所有
@polkadot/开头的依赖版本,确保@polkadot/api、@polkadot/api-contract、@polkadot/extension-dapp、@polkadot/keyring等相关包使用完全一致的版本号,禁止出现跨版本混用。 - 删除项目下的
node_modules目录和对应包管理器的锁文件(package-lock.json/yarn.lock/pnpm-lock.yaml),重新执行依赖安装命令,让包管理器将公共依赖提升到顶层目录,消除多版本@polkadot/types的重复副本。 - 修正签名逻辑,移除冗余的Keyring构造代码,直接将钱包账户地址作为
signAndSend的第一个参数传入即可,修正后的参考代码如下:
const injector = await web3FromSource(performingAccount.meta.source); const flip = await contract.tx.flip({ value: 0, gasLimit: -1 }); flip.signAndSend( performingAccount.address, { signer: injector.signer }, (result) => { if (result.status.isInBlock) { setResult("in a block"); } else if (result.status.isFinalized) { setResult("finalized"); } } );
内容的提问来源于stack exchange,提问作者s.Takahashi
相关产品推荐
相关产品推荐

