我正在将我们的React / redux项目转换为TypeScript,但是我面临TypeScript文字类型联合类型的问题。
这里是问题:
我用 type 道具(字符串)实例化 Wrapper 组件:
//index.tsx
import * as React from "react";
import { render } from "react-dom";
import "./styles.css";
import Wrapper from "./wrapper";
function App() {
return <Wrapper type="password" />;
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
我在此 Wrapper 组件中定义了字符串 type 值的“列表”应该适合。为此,我使用TypeScript Union类型:type: "value1" | value2 | ...
//Wrapper.tsx
import * as React from "react";
import Input from "./input";
import Select from "./select";
interface ILabeledInput {
type: "textarea" | "password" | "select" | "search" | "email" | "text";
}
export default function Wrapper(props: ILabeledInput) {
switch (props.type) {
case "select":
return <Select {...props} />;
case "password":
return <Input {...props} />;
}
}
在这里,无论我在 index.tsx
中定义的类型如何,都使用开关实例化适当的子组件。在子组件中,我还使用typescript接口定义 type 道具类型。 使用此开关:
- type 的类型可能只是一个字符串(只有一种可能性):
// select.tsx
import * as React from "react";
interface ISelect {
type: "select";
}
export default function Input(props: ISelect) {
return <p>{props.type}</p>; // fake code, juste to display something
}
-或再次是TypeScript Union类型的字符串(但比原始类型的可能性要小):
// input.tsx
import * as React from "react";
interface IInput {
type: "password" | "search" | "email" | "text";
}
export default function Input(props: IInput) {
return <p>{props.type}</p>; // fake code, juste to display something
}
事实 type 的类型从包装器更改为选择/输入组件会产生TypeScript错误:
Type '{ type: "textarea" | "password" | "select" | "search" | "email" | "text"; }' is not assignable to type 'ISelect'.
Types of property 'type' are incompatible.
Type '"textarea" | "password" | "select" | "search" | "email" | "text"' is not assignable to type '"select"'.
Type '"textarea"' is not assignable to type '"select"'.ts(2322)
和
Type '{ type: "textarea" | "password" | "select" | "search" | "email" | "text"; }' is not assignable to type 'IInput'.
Types of property 'type' are incompatible.
Type '"textarea" | "password" | "select" | "search" | "email" | "text"' is not assignable to type '"password" | "search" | "email" | "text"'.
Type '"textarea"' is not assignable to type '"password" | "search" | "email" | "text"'.ts(2322)
我知道Typescript检测到道具类型发生了变化,但是我找不到如何考虑开关条件的方法。
提前感谢您的帮助!
答案 0 :(得分:0)
假设我已经正确理解了它,并且我认为它可以正常工作,我试图使您的示例更简洁。这可以解决您的问题吗?
type a = 'a';
type b = 'b';
type input = 'a' | 'b';
function takeA(a: a) { }
function takeB(b: b) { }
function takeBoth(input: input) {
switch (input) {
case 'a':
return takeA(input);
case 'b':
return takeB(input);
}
}
答案 1 :(得分:0)
您可以执行以下操作:
export default function Wrapper(props: ILabeledInput) {
const {type, ...restProps} = props;
switch (type) {
case "select":
return <Select {type: 'select', ...restProps} />;
case "password":
return <Input {type: 'password', ...restProps} />;
}
}
但是,由于您声明props
的类型为ILabeledInput
,因此根据类型定义,除type
之外没有其他属性。
答案 2 :(得分:0)
非常感谢你们! 我花了整整一个下午的时间,终于找到了解决方法,它与您的解决方案alex相对应。
我已经开始破坏像你这样的道具:
import Input from "./input";
import Select from "./select";
interface ILabeledInput {
type: "textarea" | "password" | "select" | "search" | "email" | "text";
}
export default function Wrapper(props: ILabeledInput) {
const { type, ...props } = props;
switch (props.type) {
case "select":
return <Select {...props} type={type} />;
case "password":
return <Input {...props} type={type} />;
}
}
但是将props.type用作开关的参数仍然会产生问题。所以我决定发表这个话题。
我终于可以在以下解决方案中使用它了:
import * as React from "react";
import Input from "./input";
import Select from "./select";
interface ILabeledInput {
type: "textarea" | "password" | "select" | "search" | "email" | "text";
}
export default function Wrapper(props: ILabeledInput) {
switch (props.type) {
case "select":
return <Select {...props} type={props.type} />;
case "password":
return <Input {...props} type={props.type} />;
}
}
或
import * as React from "react";
import Input from "./input";
import Select from "./select";
interface ILabeledInput {
type: "textarea" | "password" | "select" | "search" | "email" | "text";
}
export default function Wrapper(props: ILabeledInput) {
const { type, ...rprops } = props;
switch (type) {
case "select":
return <Select {...rprops} type={type} />;
case "password":
return <Input {...rprops} type={type} />;
}
}
似乎switch参数应该与传递给次部件的
相同。