React组件Props传入Interface报类型作值错误的解决方法
TypeScript的类型系统仅在编译阶段生效,所有interface、type定义的类型,在代码编译为JavaScript后会被完全擦除,不存在对应的运行时实体。
你代码中用到的ISchool只是供TS做静态类型检查的标记,不是可以作为参数传递的JavaScript值,直接把它作为prop传入组件时,就会触发「类型被当作值使用」的报错。
另外你初始代码里import { InterfaceType } from "typescript"的写法也是无效的:typescript包没有导出可在运行时使用的InterfaceType值,这个概念仅存在于TS类型空间,无法在运行时访问。
你需要明确一个核心边界:TS类型空间和JS值空间是完全隔离的,所有需要在运行时用到的逻辑,都不能依赖纯TS类型实现,包括你要在组件内创建对应类型对象的需求。
你需要传入一个真实存在的运行时值作为类型结构的载体,同时让TS可以基于这个值推导出对应的静态类型,常见实现有两种:
方案1:用类作为结构载体
类在TS中是特殊的存在:它既可以作为TS类型约束实例结构,编译后也会保留为可执行的JS构造函数,是真实的运行时值,可以直接作为prop传递。
示例代码:// 定义类,同时作为类型和运行时构造器 class School { name: string = "" address: string = "" studentCount: number = 0 } // 组件Props加泛型约束 type Props<T> = { dataCtor: new () => T // 约束传入的是可通过new生成T实例的构造函数 } export default function CreateRow<T>(props: Props<T>) { // 直接调用构造函数生成符合类型的实例 const dataInstance = new props.dataCtor() return <div>{JSON.stringify(dataInstance)}</div> } // 调用组件 <CreateRow dataCtor={School} />方案2:用Schema校验对象作为结构载体
如果不想用类,可以选择Zod这类带TS类型推导的Schema校验库,Schema本身是普通JS对象,在运行时真实存在,既可以生成默认值、做数据校验,也可以反向推导出对应的TS类型,灵活度更高。
示例代码:import { z } from "zod" // 定义运行时Schema,是真实存在的JS对象 const SchoolSchema = z.object({ name: z.string().default(""), address: z.string().default(""), studentCount: z.number().default(0) }) // 从Schema推导出TS类型,不需要额外写interface type School = z.infer<typeof SchoolSchema> import { ZodType } from "zod" type Props<T extends ZodType> = { dataSchema: T } export default function CreateRow<T extends ZodType>(props: Props<T>) { // 通过Schema生成符合约束的默认对象 const dataInstance = props.dataSchema.parse({}) // 可以拿到对应TS类型做后续类型约束 type DataType = z.infer<T> return <div>{JSON.stringify(dataInstance)}</div> } // 调用组件 <CreateRow dataSchema={SchoolSchema} />
注意:不要尝试通过编译插件实现「直接传递interface」的效果,这类方案会额外增加构建链路的复杂度,兼容性和稳定性都不如上述两种通用方案。
内容的提问来源于stack exchange,提问作者Octavian Niculescu

