HarmonyOS鸿蒙Next中关于interface的奇怪问题

HarmonyOS鸿蒙Next中关于interface的奇怪问题

import { speechRecognizer } from '@kit.CoreSpeechKit';

let setListener: speechRecognizer.RecognitionListener = {
        onStart(sessionId: string, eventMessage: string) {
                console.info(`onStart, sessionId: ${sessionId} eventMessage: ${eventMessage}`);
        },
        onEvent(sessionId: string, eventCode: number, eventMessage: string) {
                console.info(`onEvent, sessionId: ${sessionId} eventCode: ${eventCode} eventMessage: ${eventMessage}`);
        },
        onResult(sessionId: string, result: speechRecognizer.SpeechRecognitionResult) {
                console.info(`onResult, sessionId: ${sessionId} sessionId: ${JSON.stringify(result)}`);
        },
        onComplete(sessionId: string, eventMessage: string) {
                console.info(`onComplete, sessionId: ${sessionId} eventMessage: ${eventMessage}`);
        },
        onError(sessionId: string, errorCode: number, errorMessage: string) {
                console.error(`onError, sessionId: ${sessionId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);
        },
}

上面的代码是正确的。

如果我自定义一个一模一样的speechRecognizer就不行了,代码如下:

// import { speechRecognizer } from '@kit.CoreSpeechKit';
declare namespace speechRecognizer {
        export interface RecognitionListener {
                onStart(sessionId: string, eventMessage: string): void;
                onEvent(sessionId: string, eventCode: number, eventMessage: string): void;
                onResult(sessionId: string, result: SpeechRecognitionResult): void;
                onComplete(sessionId: string, eventMessage: string): void;
                onError(sessionId: string, errorCode: number, errorMessage: string): void;
        }

        export interface SpeechRecognitionResult {
                isFinal: boolean;
                isLast: boolean;
                result: string;
        }

}

let setListener: speechRecognizer.RecognitionListener = {
        onStart(sessionId: string, eventMessage: string) {
                console.info(`onStart, sessionId: ${sessionId} eventMessage: ${eventMessage}`);
        },
        onEvent(sessionId: string, eventCode: number, eventMessage: string) {
                console.info(`onEvent, sessionId: ${sessionId} eventCode: ${eventCode} eventMessage: ${eventMessage}`);
        },
        onResult(sessionId: string, result: speechRecognizer.SpeechRecognitionResult) {
                console.info(`onResult, sessionId: ${sessionId} sessionId: ${JSON.stringify(result)}`);
        },
        onComplete(sessionId: string, eventMessage: string) {
                console.info(`onComplete, sessionId: ${sessionId} eventMessage: ${eventMessage}`);
        },
        onError(sessionId: string, errorCode: number, errorMessage: string) {
                console.error(`onError, sessionId: ${sessionId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);
        },
}

就会提示:

Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals) <ArkTSCheck>

为什么import系统的可以,我自己定义的就不行呢?


更多关于HarmonyOS鸿蒙Next中关于interface的奇怪问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

更多关于HarmonyOS鸿蒙Next中关于interface的奇怪问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


分析的很详细,

仔细观察一下,和系统的有什么区别呢,系统的声明是在**.d.ts里面,然后我也跟着做,把

declare namespace speechRecognizer

放在一个.d.ts文件声明,再导入,也可以。

在HarmonyOS Next中,interface主要用于定义Ability、ExtensionAbility等组件间的通信接口,支持TypeScript/ArkTS声明。其实现需遵循严格的API版本兼容性,且部分接口可能受系统权限或设备类型限制。若遇到接口未定义或调用异常,需检查API版本、权限声明及设备支持列表。

在HarmonyOS Next的ArkTS中,arkts-no-untyped-obj-literals 规则禁止使用未显式声明类型(类或接口)的对象字面量。你的自定义 declare namespace 代码在编译时,ArkTS编译器可能无法将对象字面量 { onStart(...), ... } 直接推断为与你的 speechRecognizer.RecognitionListener 接口匹配。

这是因为 declare namespace 仅提供类型声明,而 import 导入的模块除了类型,还可能包含运行时的具体实现或元信息,帮助编译器完成类型推断。要解决此问题,你有以下几种方案:

  1. 显式类型转换:创建对象字面量后,使用 as 将其断言为你的接口类型。

    let setListener: speechRecognizer.RecognitionListener = {
        onStart(sessionId: string, eventMessage: string) {
            console.info(`onStart, sessionId: ${sessionId} eventMessage: ${eventMessage}`);
        },
        // ... 其他方法
    } as speechRecognizer.RecognitionListener; // 添加类型断言
    
  2. 实现类:定义一个明确实现该接口的类。

    class MyRecognitionListener implements speechRecognizer.RecognitionListener {
        onStart(sessionId: string, eventMessage: string): void {
            console.info(`onStart, sessionId: ${sessionId} eventMessage: ${eventMessage}`);
        }
        // ... 实现其他接口方法
    }
    let setListener: speechRecognizer.RecognitionListener = new MyRecognitionListener();
    
  3. 使用对象字面量并赋值给变量:先声明一个符合接口类型的变量,再分别赋值其方法(虽然代码稍长,但可绕过此检查)。

    let setListener: speechRecognizer.RecognitionListener = {
        onStart: (sessionId: string, eventMessage: string) => {
            console.info(`onStart, sessionId: ${sessionId} eventMessage: ${eventMessage}`);
        },
        // ... 其他方法以同样的箭头函数形式定义
    };
    

根本原因:ArkTS是静态类型语言,对类型安全要求严格。import 的模块经过编译器特殊处理,能提供足够的类型上下文;而自定义的 declare namespace 在纯类型层面,对象字面量的初始化可能触发类型推断不足,因此需通过上述方式明确类型。

回到顶部