React Native与Android交互时StudentInfo类型不匹配问题求助
问题:React Native遍历studentList时元素为JSON字符串,TypeScript类型不匹配报错
问题详情
遍历从Android原生传递的studentList时,每个元素实际是JSON字符串,必须通过JSON.parse才能提取字段,但TypeScript报TS2345错误:"StudentInfo类型的参数无法赋值给string类型参数"。直接解构student会导致name和course为undefined。
相关代码
StudentsScreen.tsx
export default function StudentsScreen(props: StudentInfoProps) { const {studentList} = props; console.log(typeof studentList);//object console.log(JSON.stringify(studentList)); //["{\"name\":\"John Doe\",\"course\":\"Javascript\"}","{\"name\":\"Jane Doe\",\"course\":\"Typescript\"}","{\"name\":\"Greg Doe\",\"course\":\"ReactNative\"}"] return <> { studentList?.map(student => { console.log(typeof student);//string const {name, course} = JSON.parse(student); //I should not need to do this //const {name, course} = student; //This should be enough. However, this would cause to get undefined for name and course. return ( <Student key={uuidv4()} name={name} course={course} /> ); })} </>; }
错误信息
Screens/Students.tsx:11:53 - error TS2345: Argument of type 'StudentInfo' is not assignable to parameter of type 'string'. 11 const {name, course} = JSON.parse(student);
StudentInfo.tsx
export type StudentInfo = { name: string; course: string; }; export type StudentInfoProps = { studentList: StudentInfo[]; }; export type RootStackParamList = { ReactNative: {studentList: StudentInfoProps}; };
Android端代码(MyReactActivity.java)
public class MyReactActivity extends ReactActivity implements DefaultHardwareBackBtnHandler { private ReactInstanceManager mReactInstanceManager; private ReactRootView mReactRootView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); Gson gson = new Gson(); Bundle initialProperties = new Bundle(); Student stud1 = new Student("John Doe", "Javascript"); Student stud2 = new Student("Jane Doe", "Typescript" ); Student stud3 = new Student("Greg Doe", "React Native"); ArrayList<String> studentList = new ArrayList<>(); studentList.add(gson.toJson(stud1)); studentList.add(gson.toJson(stud2)); studentList.add(gson.toJson(stud3)); initialProperties.putStringArrayList("studentList", studentList); mReactRootView.startReactApplication(mReactInstanceManager, "RNProject", initialProperties); setContentView(mReactRootView); } }
Student.java
package com.rnproject.screens.reactnative.helpers; import java.io.Serializable; public class Student implements Serializable { private String name; private String course; public Student(){} @Override public String toString(){ return "{name="+name+",course="+course+"}"; } public Student(String name, String course){ this.name = name; this.course = course; } }
期望行为
希望能像以下示例一样直接解构对象:
const students = [{"name":"John Doe", "course":"Typescript"}, {"name":"Jane Doe", "course":"Javascript"}] const tmp = students.map(student => { const {name, course} = student; console.log(name); console.log(course); })
原因分析
Android端将每个Student对象单独序列化为JSON字符串,存入ArrayList<String>后传递给RN,导致RN接收到的是字符串数组,而非对象数组。但TypeScript类型定义中studentList被声明为StudentInfo[](对象数组),两者类型不匹配,因此出现报错。
解决方案
方案1:修改Android端代码,传递对象数组的JSON字符串
将整个学生列表序列化为单个JSON字符串,而非每个对象单独序列化:
// 替换原有的ArrayList<String>相关代码 List<Student> studentList = new ArrayList<>(); studentList.add(stud1); studentList.add(stud2); studentList.add(stud3); // 将整个列表转为JSON字符串 String studentListJson = gson.toJson(studentList); initialProperties.putString("studentList", studentListJson);
然后在RN端修改代码,先解析整个字符串为对象数组:
export default function StudentsScreen(props: { studentList: string }) { const { studentList } = props; // 解析JSON字符串为StudentInfo数组 const students: StudentInfo[] = JSON.parse(studentList); return <> { students?.map(student => { const {name, course} = student; return ( <Student key={uuidv4()} name={name} course={course} /> ); })} </>; }
同时更新StudentInfoProps类型定义:
export type StudentInfoProps = { studentList: string; };
方案2:临时兼容现有数据格式,修正TypeScript类型
如果无法修改Android端代码,可临时修正TypeScript类型,明确studentList是字符串数组,再逐个解析:
// 修改StudentInfoProps类型 export type StudentInfoProps = { studentList: string[]; }; // 在组件中使用 export default function StudentsScreen(props: StudentInfoProps) { const {studentList} = props; return <> { studentList?.map(student => { // 类型断言确保TypeScript识别解析后的类型 const {name, course} = JSON.parse(student) as StudentInfo; return ( <Student key={uuidv4()} name={name} course={course} /> ); })} </>; }
总结
方案1是更规范的做法,通过传递整个数组的JSON字符串,让RN直接解析为对象数组,避免逐个解析的麻烦;方案2是临时兼容方案,适合无法修改原生代码的场景。
内容的提问来源于stack exchange,提问作者JarochoEngineer
相关产品推荐
相关产品推荐

