Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs TypeScript:如何将类型信息从父级传递给子级?_Reactjs_Typescript - Fatal编程技术网

Reactjs TypeScript:如何将类型信息从父级传递给子级?

Reactjs TypeScript:如何将类型信息从父级传递给子级?,reactjs,typescript,Reactjs,Typescript,给定以下表单及其(非受控)输入子项: <Form initialValues={{ firstName: "", lastName: "", age: "" }}> <Input label="First name" name="firstName" /> <Input label="Last name" name="lastNa

给定以下
表单
及其(非受控)
输入
子项:

<Form initialValues={{ firstName: "", lastName: "", age: "" }}>
  <Input label="First name" name="firstName" />
  <Input label="Last name" name="lastName" />
  <Input label="Age" name="age" />
</Form>

我希望
输入
名称
道具的类型为
“firstName”|“lastName”|“age”
。此类型应派生自
表单
初始值

实现这一目标最干净的方法是什么



注意:在一般情况下,表单输入组件应该是可树摇动的。

不确定输入是如何定义的,但我会使用formname类型为输入组件创建一个formname类型和一个接口

键入FormName=“firstName”|“lastName”|“age”;
接口输入道具{
姓名:FormName
}
//或
接口输入道具{
姓名:“名字”|“姓氏”|“年龄”
}
常量输入:FC=(props):JSX.Element=>{
};

您可以使用
keyof

type initialValues = {
  firstName: string;
  lastName: string;
  age: string
}

type inputName = keyof initialValues;

let age: inputName = "age"; //valid
let middleName: inputName = "middleName"; //invalid

编辑:我觉得我遗漏了什么,但这里有一个代码沙盒,展示了我将如何实现它:


这样的事情不可能吗?
表单
输入
是否由第三方模块提供?

您只需在此限制您的
输入
组件的属性
名称
,可以这样实现:

导出类型InputName=“firstName”|“lastName”|“age”
导出接口InputProps{
名称:InputName
}
常量输入:React.FC=(道具)=>{
常量{name}=props
// ...
}
然而,这意味着应用程序中的每个
输入都应该有一个这样的名称,我很确定这不是你想要的

为确保特定的
表单中的每个
输入
组件具有以下名称之一,您需要定义一个新的自定义组件,该组件将扩展默认行为:

specific form.tsx

从“组件/表单”导入表单
从“组件/输入”导入输入,{InputProps}
导出类型SpecificInputName=“firstName”|“lastName”|“age”
导出接口SpecificInputProps扩展InputProps{
名称:InputName
}
导出类型SpecificFormComponent=React.FC&{Input:React.FC}
常量SpecificForm:SpecificFormComponent=(道具)=>{
返回{props.children}
}
const SpecificInput:React.FC=(道具)=>{
返回
}
SpecificForm.Input=SpecificInput
导出默认特定表单
然后你可以像这样消费它:

从“./components/SpecificForm”导入表单

此信息无法自动推断。您必须以某种方式手动提供该类型。临时解决方案如下所示:

function App() {
  const initialValues = {
    firstName: 'string',
    lastName: 'string',
    age: 'string',
  }

  const MyInput: React.FC<{ label: string, name: keyof typeof initialValues }> = Input
  return <Form initialValues={initialValues}>
    <MyInput label="First name" name="firstNameWRONG" /> // error
    <MyInput label="Last name" name="lastName" />
    <MyInput label="Age" name="age" />
  </Form>
}
首先,如果要引发任何类型错误,则应通过
parentElement
行而不是
childElement
行引发。违反的是父组件的协议,该协议规定“子组件的
名称
应为
keyof initValue
”。这种验证是通过
React.createElement
函数针对其参数进行的

其次,从类型系统的角度来看,如果我们能够从
parentProps
推断
childProps
的类型,那么解析过程应该如下所示:

1. let `Parent` be generic type of form
   Component<T, E<_>> = (props: { initValues: T, children: E<keyof T> }) => Element<any>
2. let `Child` be generic type of form
   Component<K> = (props: { name: K }) => Element<K>
3. from `childElement = React.createElement(Child, childProps))`
   we know `childElement` is type `Element<string>`
4. from `parentElement = React.createElement(Parent, parentProps, childElement)`
   we know about `T` and `E = Element` and `_ = keyof T`
5. now we need to allow prioritze `E<_>` rule over `Element<string>`, thus override `childElement` from `Element<string>` to `Element<keyof T>`
但我们的意思是

fill<T>(arg0: T, arg1: Element<T>)
fill(arg0:T,arg1:Element)
顺便说一句,从来没有一个类型系统支持这种行为,更不用说TS一开始甚至不支持更高级的类型

--

更新 我认为值得一提的是,理论上有可能从
表单
关于
名称
属性的
输入
不符合协议的情况下引发类型错误。但是,这不能用JSX实现,只能通过
React.createElement
实现


这是因为TS将所有JSX创建的元素分配给特殊的内置接口
JSX.Element
。react对其进行了扩展,以扩展注释中提供的
react.ReactElement。

您的意思是要使用循环来创建三个输入,而不是对其进行硬编码?为什么不简单地使用受控输入?将它们的值存储在其父级的状态中,使用“值”字段将这些值传递给它们,并在使用onChange回调的输入时更新父级的状态。在这里,您可以找到一些解决方法缺少一个关键点。
输入
如何在传递给父
表单
初始值
上执行
keyof
?这种方法的缺点是表单组件不会发生树抖动。假设您有10个不同的表单输入组件,如
input
Select
RadioGroup
,等等。如果用户创建了一个包含2个
input
字段的简单表单,那么它们应该只包括其捆绑包中的
表单
input
组件。根据您的方法,所有10个组件都将包括在内,因为它们都是在
表单上定义的。您是对的,这就是为什么这个组件需要是一个特定的组件(如
LoginForm
),您一定要使用它(如果您不使用它,就没有理由创建它).该问题提到了驱动该类型的
表单
。你的回答没有多大意义,因为我没有看到
表单。
fill<T>(arg0: T, arg1: Element<T>)