You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KotlinJS中is运算符为何不遵循继承规则?

KotlinJS中Number继承类的is判断异常问题

问题场景

我在开发KotlinJS React项目,使用的插件配置:

plugins {
    kotlin("js") version "1.8.0"
}

定义了继承自Number的Percentage类:

class Percentage(private val number: Number) : Number() {
    override fun toByte() = number.toByte()
    override fun toChar() = number.toChar()
    override fun toDouble() = number.toDouble()
    override fun toFloat() = number.toFloat()
    override fun toInt() = number.toInt()
    override fun toLong() = number.toLong()
    override fun toShort() = number.toShort()
    override fun toString() = "$number%"
}

但执行以下代码时,控制台输出false,尽管IDEA提示“该实例检查始终为true”:

if (value is Percentage) {
    println(value is Number)
}

原因分析

这是KotlinJS底层实现特性导致的:

  • 在Kotlin/JVM中,Number是所有数值类型的父类,继承关系在字节码层面正常体现,is判断符合预期。
  • 但在KotlinJS中,Number会被编译为JavaScript原生Number类型,而自定义继承Number的Kotlin类,最终会被编译成普通JS对象,不会成为原生Number的实例。
  • Kotlin的is运算符在JS平台对应JavaScript的instanceof,后者通过原型链判断类型,自定义类的原型链和原生Number不重合,因此value is Number返回false。

解决方案

  • 改用组合模式替代继承:不再继承Number,将Number作为成员变量,按需暴露数值转换方法:

    class Percentage(private val number: Number) {
        fun toByte() = number.toByte()
        fun toChar() = number.toChar()
        fun toDouble() = number.toDouble()
        fun toFloat() = number.toFloat()
        fun toInt() = number.toInt()
        fun toLong() = number.toLong()
        fun toShort() = number.toShort()
        override fun toString() = "$number%"
    }
    

    若需要统一判断数值相关类型,可自定义接口或直接检查成员变量类型。

  • 自定义类型判断逻辑:如果必须保留继承关系,可扩展属性实现兼容判断:

    val Any.isNumberLike: Boolean
        get() = this is Number || this is Percentage
    

    使用时用value.isNumberLike替代value is Number。

  • 升级Kotlin版本:后续Kotlin版本(如1.9.x及以上)优化了JS平台的Number继承处理,可尝试升级插件版本到最新稳定版:

    plugins {
        kotlin("js") version "1.9.20"
    }
    

内容的提问来源于stack exchange,提问作者raven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 03:45:29