================================================================================ UTS-Android 兼容性开发规范 ================================================================================ > 以下为 uni-app-x (UTS) Android 端开发常见注意事项与踩坑点,建议所有开发成员遵循: ================================================================================ 一、基础语法规范 ================================================================================ 1. 变量声明 - 只能使用 let 和 const,不能使用 var - 变量声明必须有显式类型或初始化值 - 不支持 undefined 类型,变量未赋值就是 null - 不支持 undefined 关键字,判断是否存在要用 != null 2. 类型定义 - 只适合转 type,不适合使用 interface(interface 在 kotlin/swift 中另有不同) - 不支持 Intersection Type(交叉类型) - 不支持 Index Signature(索引签名) - 类型推断严格,必要时用 as Type 明确类型 - 不支持内联对象类型(Object Literal Type),需要单独定义 type 3. 函数定义 - 函数必须在使用前定义(不支持函数提升) - 在 setup 模式下,调用的函数必须在调用之前定义 - 依赖关系需要明确:被调用的函数必须先定义 - 这与 JavaScript 的函数提升行为不同,UTS 更接近 C/Java 的编译方式 4. 循环 - for 循环的 i 必须写明类型:let i: Int = 0 - 不要用 forEach、map,数组遍历用 for 循环 - 嵌套的数组方法调用可能导致类型推断失败,应改用 for 循环 ================================================================================ 二、类型与对象访问 ================================================================================ 1. any 类型访问 - 不能直接访问 any 类型对象的属性 - 需要将对象转换为 UTSJSONObject 类型后使用 getString()、getNumber() 等方法访问属性 - any 类型属性访问需转换为 Record 后用索引访问 - 使用索引访问属性时,推荐使用方括号语法 obj['property'] 而非点语法 obj.property - any 类型不支持索引访问 obj['key'],必须先转换为 UTSJSONObject 2. UTSJSONObject 使用 - 用 utils/utis 下的 UTSJSONObject 做类型转换 - 不要用 safeget,只要 UTSJSONObject 就好了 - 需要创建动态对象时,应使用 new UTSJSONObject() 然后调用 .set() 方法 - 对于 type 定义的对象类型,同样需要使用 UTSJSONObject - 使用 getString()、getNumber() 方法获取属性值 3. 数组类型 - 数组类型建议写成 Array,不要用 Type[] 简写 - 空数组需要明确指定类型,如 [] as string[] - 数组元素需要明确的类型定义才能在模板中正确访问属性 - 对于 any[] 或 reactive 数组,访问元素属性时需要先转换为 Record 或 any[] 4. 对象操作 - 不支持 Object.keys()、Object.values()、Object.entries() - 不支持 Record 对象字面量语法 - 对象字面量 {...} 只能用于构造类型(class),不能用于接口(interface) - reactive 对象在 UTS 中不支持索引器赋值操作 ================================================================================ 三、条件判断与逻辑运算 ================================================================================ 1. if 条件 - if 判断只接受 boolean 类型,不能是其他类型的值 - 判断空要用 !== null,不能用 !变量(uts android 不支持 !在变量前面的判断空方式) - 模板中的 || 运算符左边必须是 boolean 类型 - 可空类型使用可选链 ?. 和空值合并 ?? - 字符串判断空要用:variable != null && variable !== '' 2. 逻辑运算符 - || 表示逻辑或 - && 表示逻辑与 - ! 表示逻辑非(但 !变量 不支持用于判断空) - ?? 表示空值合并运算符(当左侧为 null 时返回右侧值) - ts 的为空则使用默认值的语法在 uts 中不能用 ||,要用 ?? 来代替 ================================================================================ 四、组件与模板 ================================================================================ 1. 表单与输入 - 表单优先用 form 组件 - 不支持 uni-easyinput,用 input 代替 - 时间选择用 uni_modules/lime-date-time-picker 2. 选择器 - uts android 不支持 picker,用 picker-view 或 uni.showActionSheet - 一维的优先用 uni.showActionSheet - picker-view 的事件用 UniPickerViewChangeEvent 3. 导航与布局 - 不支持 uni-nav-bar,先删除 - 不支持 uni-data-select,用 picker-view 代替 - 不支持 uni-datetime-picker,用 components/picker-date 或 components/picker-time 代替 - 不支持 uni-icons 4. 模板注意事项 - 跟 template 交互的变量尽量用一维变量(不要嵌套对象) - 模板中可空类型必须使用 ?. 安全访问 - 模板中访问可空类型属性前必须先判空 v-if="order != null" ================================================================================ 五、CSS 样式限制 ================================================================================ 1. 布局方式 - 只支持 display: flex - 不支持 display: grid - 不支持 gap - 不支持 table、grid、grid-template-columns 2. 单位与计算 - 不支持 calc() - 不支持的单位: vh - property value `100%` is not supported for min-height (supported values are: number|pixel) - property value `calc(33.33% - 10px)` is not supported for min-width 3. 选择器 - [APP-ANDROID] 不支持伪类选择器 - [APP-IOS] 不支持伪类选择器 - ERROR: Selector `.login-button[disabled]` is not supported. uvue only support classname selector 4. 其他样式 - WARNING: `backdrop-filter` is not a standard property name - style property `white-space` is only supported on `| ``` 3. Map 类型访问限制 - UTS Android 不支持 Map 类型的 get() 方法访问属性 - 应统一使用 UTSJSONObject - 示例: ```typescript // 错误 const m = item as Map const idVal = m.get('id') // 正确 const itemObj = item as UTSJSONObject const id = itemObj.getString('id') ?? '' ``` 4. 函数内取反操作符 - if (!isValid.value) 不支持取反 - 使用 if (isValid.value === false) - 示例: ```typescript // 错误 if (!isValid.value) return // 正确 if (isValid.value === false) return ``` ================================================================================ 二十一、2026-02-25 user 目录页面修复记录 ================================================================================ 1. change-password.uvue 修复 - 问题:!oldPassword.value 取反操作不支持 - 修复:改为 oldPassword.value == '' 显式判断 - 问题:const { error } = await ... 解构赋值不支持 - 修复:改为 const result = await ... 然后 result.error 访问 2. login.uvue 修复 - 问题:as unknown as number 双重类型转换不支持 - 修复:改为 as number 单一类型转换 - 问题:typeof err === 'object' 不支持 - 修复:使用 try-catch 包裹类型转换 3. forgot-password.uvue 修复 - 问题:!emailRegex.test(this.email) 取反操作不支持 - 修复:改为 emailRegex.test(this.email) == false - 问题:typeof err === 'object' 不支持 - 修复:使用 try-catch 包裹类型转换 4. register.uvue 修复 - 问题:!protocol.value 取反操作不支持 - 修复:改为 protocol.value == false - 问题:!validateEmail() 等取反操作不支持 - 修复:改为 validateEmail() == false ================================================================================ 二十二、常见修复模式速查 ================================================================================ 1. 取反操作修复模式 ```typescript // 错误 if (!variable) { ... } if (!isValid.value) { ... } if (!validate()) { ... } // 正确 - 根据类型选择 if (variable == null || variable == '') { ... } // 字符串判空 if (isValid.value == false) { ... } // 布尔值取反 if (validate() == false) { ... } // 函数返回布尔值取反 ``` 2. 解构赋值修复模式 ```typescript // 错误 const { data, error } = await someAsyncCall() // 正确 const result = await someAsyncCall() const data = result.data const error = result.error ``` 3. typeof 检查修复模式 ```typescript // 错误 if (typeof err === 'object') { ... } if (typeof xxx === 'function') { ... } // 正确 try { const e = err as Error // 使用 e } catch (e2) { // 处理转换失败 } ``` 4. as unknown as 修复模式 ```typescript // 错误 const timer = setInterval(...) as unknown as number // 正确 const timer = setInterval(...) as number ``` ================================================================================ 二十三、错误处理最佳实践 ================================================================================ 1. 统一错误处理模式 ```typescript try { const result = await someAsyncCall() if (result.error != null) { const errorMsg = (result.error as Error).message uni.showToast({ title: errorMsg, icon: 'none' }) return } // 处理成功结果 } catch (e) { console.error('操作失败:', e) uni.showToast({ title: '操作失败', icon: 'none' }) } ``` 2. 可空类型安全访问 ```typescript // 安全访问对象属性 const value = obj != null ? obj.property : null // 安全调用方法 const result = obj != null ? obj.method() : null ``` 3. 数组安全访问 ```typescript // 安全访问数组元素 if (arr.length > index) { const item = arr[index] // 使用 item } ``` ================================================================================ 文档结束 ================================================================================ ================================================================================ 二十四、2026-02-27 函数可选参数限制(重要) ================================================================================ 1. 可选参数不能跳过传递 - UTS Android 不支持跳过可选参数传递 - 如果函数有多个可选参数,必须按顺序传递所有参数 - 错误示例: ```typescript // 函数定义 async addToCart(productId: string, quantity: number = 1, skuId?: string, merchantId?: string): Promise // 错误调用 - 跳过了 merchantId 参数 await supabaseService.addToCart(productId, 1, '') // 编译错误:No value passed for parameter 'merchantId' ``` - 正确示例: ```typescript // 方案1:给可选参数添加默认值 async addToCart(productId: string, quantity: number = 1, skuId: string = '', merchantId: string = ''): Promise // 方案2:调用时传递所有参数 await supabaseService.addToCart(productId, 1, '', '') ``` 2. 可选参数定义规范 - 推荐使用 `param: Type = defaultValue` 而非 `param?: Type` - `param?: Type` 在 Android 端调用时仍需传递参数 - `param: Type = defaultValue` 可以在不传参时使用默认值 - 示例: ```typescript // 不推荐 - 调用时仍需传递参数 function foo(a: string, b?: string, c?: string): void // 推荐 - 可以跳过参数使用默认值 function foo(a: string, b: string = '', c: string = ''): void ``` 3. 编译错误提示 - 错误信息:"No value passed for parameter 'xxx'" - 原因:可选参数在 Android 端不能跳过 - 解决: 1. 修改函数签名,使用默认值 `param: Type = defaultValue` 2. 调用时传递所有参数 4. 最佳实践 - 对于有多个可选参数的函数,统一使用默认值语法 - 调用时显式传递所有参数,避免依赖可选参数跳过 - 在服务层函数定义中,优先使用 `= ''` 或 `= 0` 等默认值 ================================================================================ 二十五、2026-02-27 模板中的非空断言限制(重要) ================================================================================ 1. 模板中不支持非空断言操作符 `!` - UTS Android 模板中不能使用 `variable!` 非空断言 - 错误示例: ```html ``` - 正确示例: ```html ``` 2. 编译错误提示 - 错误信息:"参数类型不匹配:实际类型为 'Number?',预期类型为 'Number'" - 原因:模板中使用非空断言 `!` 不被支持 - 解决:移除非空断言 `!`,直接使用变量进行比较 3. 最佳实践 - 在模板中,先用 `!= null` 判断可空类型,然后直接使用变量 - UTS 编译器会在 `!= null` 判断后自动识别变量为非空类型 ================================================================================ 二十六、2026-02-27 未导入类型的处理(重要) ================================================================================ 1. 未导入的类型不能直接使用 - 在页面中使用的类型必须先导入或使用 UTSJSONObject 替代 - 错误示例: ```typescript // Shop 类型未导入 const s = shopRespData[i] as Shop const id = s.id // 找不到名称 "id" ``` - 正确示例: ```typescript // 使用 UTSJSONObject const s = shopRespData[i] as UTSJSONObject const id = s.getString('id') ?? '' const name = s.getString('shop_name') ?? '' ``` 2. 编译错误提示 - 错误信息:"找不到名称 'XXX'" - 原因:类型未导入或类型定义不存在 - 解决: 1. 导入需要的类型:`import { Shop } from '@/utils/supabaseService.uts'` 2. 使用 UTSJSONObject 替代:`as UTSJSONObject` 然后用 `getString()`、`getNumber()` 访问属性 3. 最佳实践 - 对于简单的数据转换,推荐使用 UTSJSONObject - 避免在多个文件中重复定义相同的类型 - 如果需要类型安全,从服务层导入类型定义 ================================================================================ 二十七、2026-02-27 服务层数据字段完整性(重要) ================================================================================ 1. 服务层返回数据必须包含所有必要字段 - 从数据库获取数据时,必须正确映射所有需要的字段 - 错误示例: ```typescript const product: Product = { id: prodObj.getString('id') ?? '', name: prodObj.getString('name') ?? '', // 错误:merchant_id 硬编码为空字符串 merchant_id: '' } as Product ``` - 正确示例: ```typescript const product: Product = { id: prodObj.getString('id') ?? '', name: prodObj.getString('name') ?? '', // 正确:从数据库获取 merchant_id merchant_id: prodObj.getString('merchant_id') ?? '' } as Product ``` 2. 调用服务层方法时必须传递完整参数 - 页面调用服务层方法时,需要传递所有必要参数 - 错误示例: ```typescript // 错误:merchant_id 传空字符串 await supabaseService.addToCart(productId, 1, '', '') ``` - 正确示例: ```typescript // 正确:从商品对象获取 merchant_id const merchantId = product.merchant_id ?? '' await supabaseService.addToCart(productId, 1, '', merchantId) ``` 3. 编译错误提示 - 问题表现:数据添加到数据库失败,或添加的数据不完整 - 原因:服务层或页面层缺少必要字段的传递 - 解决: 1. 检查服务层数据映射是否完整 2. 检查页面调用时是否传递了所有必要参数 4. 最佳实践 - 服务层方法返回的对象应包含数据库视图的所有字段 - 页面调用服务层方法时,应从数据对象中获取并传递所有参数 - 对于关联数据(如 merchant_id),确保在数据加载时一并获取 ================================================================================ 二十八、2026-02-27 模板中的非运算符限制(重要) ================================================================================ 1. 模板中不支持 `!` 非运算符 - UTS Android 模板中不能使用 `!variable` 非运算符 - 错误示例: ```html ``` - 正确示例: ```html ``` 2. 编译错误提示 - 错误信息:"找不到名称'not'" - 原因:模板中不支持非运算符 `!` - 解决:使用显式的比较表达式替代 3. 最佳实践 - 使用 `== null` 或 `== ''` 检查空值 - 使用 `!= null && != ''` 检查非空值 ================================================================================ 二十九、2026-02-27 索引访问限制(重要) ================================================================================ 1. 不支持 `(obj as any)['key']` 索引访问方式 - UTS Android 不支持对 any 类型使用索引访问 - 错误示例: ```typescript const detail = (e as any)['detail'] val = detail['value'] ?? '' ``` - 正确示例: ```typescript // 方案1:使用 UTSJSONObject const eObj = JSON.parse(JSON.stringify(e)) as UTSJSONObject const detail = eObj.get('detail') as UTSJSONObject val = detail.getString('value') ?? '' // 方案2:先判断类型再转换 if (e instanceof UTSJSONObject) { const eObj = e as UTSJSONObject const detail = eObj.get('detail') as UTSJSONObject val = detail.getString('value') ?? '' } ``` 2. 编译错误提示 - 错误信息:"Unresolved reference. None of the following candidates is applicable because of a receiver type mismatch" - 原因:any 类型不支持索引访问 - 解决:转换为 UTSJSONObject 后使用 `.get()` 方法 3. 最佳实践 - 统一使用 UTSJSONObject 处理动态对象 - 使用 `.get()`、`.getString()`、`.getNumber()` 方法访问属性 - 对于复杂对象,先用 `JSON.parse(JSON.stringify(obj))` 转换 ================================================================================ 三十、2026-02-27 字符串不能直接作为布尔条件(重要) ================================================================================ 1. 字符串不能直接作为 if 条件 - UTS Android 不支持将字符串直接作为布尔条件判断 - 错误示例: ```typescript const paramId = '123' if (paramId) { // 错误:字符串不能直接作为布尔条件 // ... } ``` - 正确示例: ```typescript const paramId = '123' if (paramId != null && paramId != '') { // 正确:显式判断 // ... } ``` 2. 编译错误提示 - 错误信息:"Condition type mismatch: inferred type is 'String' but 'Boolean' was expected" - 原因:字符串类型不能直接作为布尔条件 - 解决:使用显式的比较表达式 3. 最佳实践 - 使用 `!= null && != ''` 检查字符串非空 - 使用 `== null || == ''` 检查字符串为空 ================================================================================ 三十一、2026-02-27 函数定义顺序(重要) ================================================================================ 1. 函数必须在调用前定义 - UTS Android 要求函数在调用之前完成定义 - 这与 JavaScript 的函数提升不同 - 错误示例: ```typescript onMounted(() => { loadData() // 错误:loadData 还未定义 }) const loadData = async () => { // ... } ``` - 正确示例: ```typescript const loadData = async () => { // ... } onMounted(() => { loadData() // 正确:loadData 已定义 }) ``` 2. 编译错误提示 - 错误信息:"找不到名称'xxx'" - 原因:函数在调用点之后定义 - 解决:将函数定义移到调用之前 3. 最佳实践 - 将所有函数定义放在生命周期钩子(onMounted、onShow 等)之前 - 按依赖关系排序函数定义顺序 ================================================================================ 三十二、2026-02-27 联合类型属性访问(重要) ================================================================================ 1. 联合类型不能直接访问属性 - 当参数类型为联合类型(如 `A | B`)时,不能直接访问属性 - 错误示例: ```typescript type A = { id: string, name: string } type B = { id: string, title: string } const foo = (item: A | B) => { const id = item.id // 错误:联合类型不能直接访问属性 } ``` - 正确示例: ```typescript const foo = (item: A | B) => { // 方案1:转换为 UTSJSONObject const obj = JSON.parse(JSON.stringify(item)) as UTSJSONObject const id = obj.getString('id') ?? '' // 方案2:使用类型守卫 if ('name' in item) { const id = item.id // 此时类型已收窄为 A } } ``` 2. 编译错误提示 - 错误信息:"找不到名称'xxx'" - 原因:联合类型的属性访问受限 - 解决:转换为 UTSJSONObject 或使用类型守卫 3. 最佳实践 - 对于联合类型参数,统一转换为 UTSJSONObject 处理 - 使用 `.getString()`、`.getNumber()` 等方法安全访问属性 ================================================================================ 三十三、2026-02-27 any 类型变量不能赋值为 null(重要) ================================================================================ 1. any 类型变量不能赋值为 null - UTS Android 中 `any` 类型不能赋值为 `null` - 错误示例: ```typescript let res: any = null // 错误:Null cannot be a value of a non-null type 'Any' ``` - 正确示例: ```typescript let res: any = {} // 正确:使用空对象 // 或者 let res: any | null = null // 使用联合类型 ``` 2. 编译错误提示 - 错误信息:"Null cannot be a value of a non-null type 'Any'" - 原因:any 类型不允许 null 值 - 解决:使用空对象 `{}` 或联合类型 `any | null` ================================================================================ 三十四、2026-02-27 对象字面量类型推断问题(重要) ================================================================================ 1. 对象字面量直接赋值给 ref 可能类型不匹配 - 当对象字面量直接赋值给特定类型的 ref 时,可能报类型不匹配错误 - 错误示例: ```typescript merchant.value = { id: shop.id, user_id: shop.merchant_id, // ... } // 错误:Assignment type mismatch ``` - 正确示例: ```typescript // 方案1:显式声明类型 const merchantData: MerchantType = { id: shop.id, user_id: shop.merchant_id, // ... } merchant.value = merchantData // 方案2:使用 as 类型断言 merchant.value = { id: shop.id, user_id: shop.merchant_id, // ... } as MerchantType ``` 2. 编译错误提示 - 错误信息:"Assignment type mismatch: actual type is '', but 'XXX' was expected" - 原因:对象字面量被推断为匿名类型 - 解决:显式声明类型或使用类型断言 ================================================================================ 三十五、2026-02-27 any 类型不能直接访问属性(重要) ================================================================================ 1. any 类型参数不能直接访问属性 - 在 map、forEach 等回调中,any 类型的参数不能直接访问属性 - 错误示例: ```typescript const list = rawList.map((item): ProductType => { const id = item.id // 错误:找不到名称"id" const name = item.name // 错误:找不到名称"name" }) ``` - 正确示例: ```typescript const list = rawList.map((item: any): ProductType => { // 方案1:转换为 UTSJSONObject const itemObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject const id = itemObj.getString('id') ?? '' const name = itemObj.getString('name') ?? '' // 方案2:显式标注参数类型并使用索引 // 注意:这种方式在 UTS Android 中也可能有问题 }) ``` 2. 编译错误提示 - 错误信息:"找不到名称'xxx'" - 原因:any 类型的属性访问受限 - 解决:转换为 UTSJSONObject 后使用 `.getString()` 等方法 ================================================================================ 三十六、2026-02-27 类型断言不会添加方法(重要) ================================================================================ 1. `as UTSJSONObject` 不会给对象添加方法 - 使用 `as UTSJSONObject` 只是类型断言,不会让普通对象获得 `getString` 等方法 - 错误示例: ```typescript const profileObj = profile as UTSJSONObject const id = profileObj.getString('user_id') // 运行时错误:getString is not a function ``` - 正确示例: ```typescript // 必须使用 JSON.parse(JSON.stringify()) 进行真正的转换 const profileObj = JSON.parse(JSON.stringify(profile)) as UTSJSONObject const id = profileObj.getString('user_id') ?? '' ``` 2. 运行时错误提示 - 错误信息:"XXX is not a function" - 原因:类型断言只是编译时行为,不会改变运行时对象的方法 - 解决:使用 `JSON.parse(JSON.stringify())` 进行真正的对象转换 3. 最佳实践 - 对于从 API 返回的数据,统一使用 `JSON.parse(JSON.stringify())` 转换 - 使用 `instanceof UTSJSONObject` 检查对象类型 - 不要依赖 `as` 类型断言来添加方法 ================================================================================ 三十七、2026-02-27 类型必须包含所有必填字段(重要) ================================================================================ 1. 创建类型实例时必须包含所有必填字段 - UTS 类型定义中的非可选字段(不带 `?`)都是必填的 - 错误示例: ```typescript export type ProductType = { id: string merchant_id: string // 必填 category_id: string // 必填 name: string // ... } // 错误:缺少 merchant_id、category_id 等必填字段 return { id: item.id, name: item.name, price: item.price } as ProductType // 运行时错误:missing required property ``` - 正确示例: ```typescript return { id: itemObj.getString('id') ?? '', merchant_id: itemObj.getString('merchant_id') ?? '', category_id: itemObj.getString('category_id') ?? '', name: itemObj.getString('name') ?? '未知商品', description: itemObj.getString('description') ?? '', images: images, price: itemObj.getNumber('base_price') ?? 0, original_price: itemObj.getNumber('market_price') ?? 0, stock: itemObj.getNumber('total_stock') ?? 0, sales: itemObj.getNumber('sale_count') ?? 0, status: 1, created_at: itemObj.getString('created_at') ?? '' } as ProductType ``` 2. 运行时错误提示 - 错误信息:"Failed to construct type, missing required property: xxx" - 原因:类型定义中有必填字段未提供 - 解决: 1. 检查类型定义,确认所有必填字段 2. 为所有必填字段提供值,即使是空字符串或默认值 3. 最佳实践 - 查看类型定义,确认哪些字段是必填的(不带 `?`) - 使用 `??` 运算符提供默认值 - 对于可选字段,可以不提供或使用 `null` ================================================================================ 三十八、2026-02-27 回调函数不能是 async(重要) ================================================================================ 1. API 回调函数不能使用 async 修饰 - uni API 的回调函数(如 showModal 的 success)不支持 async 函数 - 错误示例: ```typescript uni.showModal({ title: '确认', content: '确定要删除吗?', success: async (res) => { // 错误:回调函数不能是 async if (res.confirm) { const result = await someAsyncFunction() } } }) ``` - 正确示例: ```typescript uni.showModal({ title: '确认', content: '确定要删除吗?', success: (res) => { if (res.confirm) { // 使用 Promise.then() 代替 await someAsyncFunction().then((result) => { // 处理结果 }) } } }) ``` 2. 编译错误提示 - 错误信息:"参数类型不匹配:实际类型为 'Function1<..., UTSPromise>',预期类型为 'Function1<..., Unit>?'" - 原因:回调函数返回 Promise 而非 void - 解决:使用 `.then()` 代替 `await` 3. 最佳实践 - 在回调函数中使用 `.then()` 处理异步操作 - 将异步逻辑封装为单独的函数,在回调中调用 ================================================================================ 三十九、2026-02-27 类型转换前必须检查类型(重要) ================================================================================ 1. 使用 `as` 类型转换前必须检查实际类型 - 直接使用 `as string` 转换可能导致运行时类型转换异常 - 错误示例: ```typescript const idVal = item['id'] const id = idVal as string // 错误:如果 idVal 是其他类型会崩溃 ``` - 正确示例: ```typescript const idVal = item['id'] const id = (idVal != null && typeof idVal == 'string') ? (idVal as string) : '' ``` 2. 运行时错误提示 - 错误信息:"null cannot be cast to non-null type kotlin.String" - 错误信息:"java.lang.Boolean cannot be cast to java.lang.String" - 原因:直接类型转换时,实际类型与目标类型不匹配 - 解决:使用 `typeof` 检查类型后再转换 3. 最佳实践 - 使用 `typeof` 检查类型 - 使用 `!= null` 检查空值 - 提供默认值防止空指针异常 ================================================================================ 四十、2026-02-27 UTSJSONObject 必须正确转换(重要) ================================================================================ 1. `as UTSJSONObject` 不会添加方法 - 从数据库返回的数据需要正确转换为 UTSJSONObject - 错误示例: ```typescript const item = rawList[i] const brandObj = item as UTSJSONObject // 错误:brandObj.getString 不存在 ``` - 正确示例: ```typescript const item = rawList[i] const brandObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject const id = brandObj.getString('id') ?? '' ``` 2. 运行时错误提示 - 错误信息:"getString is not a function" - 原因:对象没有正确转换为 UTSJSONObject - 解决:使用 `JSON.parse(JSON.stringify())` 进行转换 3. 最佳实践 - 对于从数据库/API 返回的数据,统一使用 `JSON.parse(JSON.stringify())` 转换 - 使用 `.getString()`、`.getNumber()` 等方法安全访问属性 ================================================================================ ================================================================================