如何使用 TypeScript 为无状态的功能性 React 组件指定(可选)默认道具?

我正在尝试创建一个无状态的 React 组件,其中包含可选的道具和 Typecript 中的 defaultProps (针对 React 本机项目)。对于普通的 JS 来说,这是微不足道的,但是对于如何在 TypeScript 中实现它,我感到很困惑。

密码如下:

import React, { Component } from 'react';
import { Text } from 'react-native';


interface TestProps {
title?: string,
name?: string
}


const defaultProps: TestProps = {
title: 'Mr',
name: 'McGee'
}


const Test = (props = defaultProps) => (
<Text>
{props.title} {props.name}
</Text>
);


export default Test;

调用 <Test title="Sir" name="Lancelot" />会像预期的那样显示“兰斯洛特爵士”,但是 <Test />在应该输出的时候什么结果也没有 “ McGee 先生”。

非常感谢您的帮助。

158876 次浏览

对我来说,听着不像是打字稿的问题。

免责声明: 我只在打字机上试过这个。

但是,问题在于支持 一直都是存在(即使在没有传入任何内容的情况下,它也是一个空对象)。不过,有两种解决办法。

不幸的是,第一种方法破坏了您所拥有的超级干净的无花括号语法,但是让我们保留 defaultProps

interface TestProps {
title?: string;
name?: string;
}


const defaultProps: TestProps = {
title: 'Mr',
name: 'McGee'
}


const Test = (passedIn: TestProps) => {
const props = Object.assign({}, defaultProps, passedIn);
return (
<p>
{props.title} {props.name}
</p>
);
}

如果你有一吨的道具,另一个选择可能会有点棘手,但是让你保持原来的语法是这样的:

const Test = (props: TestProps) => (
<Text>
{props.title || 'Mr'} {props.name || 'McGee'}
</Text>
);

希望这个能帮上忙!

这里有一个类似的问题和答案: 在无状态函数中使用 TypeScript 定义 defaultProps 进行响应

import React, { Component } from 'react';
import { Text } from 'react-native';


interface TestProps {
title?: string,
name?: string
}


const defaultProps: TestProps = {
title: 'Mr',
name: 'McGee'
}


const Test: React.SFC<TestProps> = (props) => (
<Text>
{props.title} {props.name}
</Text>
);


Test.defaultProps = defaultProps;


export default Test;

I've found the easiest method is to use optional arguments. Note that defaultProps will eventually be 不推荐使用功能性组件.

例如:

interface TestProps {
title?: string;
name?: string;
}


const Test = ({title = 'Mr', name = 'McGee'}: TestProps) => {
return (
<p>
{title} {name}
</p>
);
}

我喜欢这样做:

type TestProps = { foo: Foo } & DefaultProps
type DefaultProps = Partial<typeof defaultProps>
const defaultProps = {
title: 'Mr',
name: 'McGee'
}


const Test = (props: Props) => {
props = {...defaultProps, ...props}
return (
<Text>
{props.title} {props.name}
</Text>
)
}


export default Test

将我的解决方案添加到现有解决方案中,我认为它为现有解决方案增加了额外的可读性和优雅性。

假设您有一个具有所需和可选道具组合的组件 MyComponent。我们可以将这些必需道具和可选道具分成两个接口,将它们组合起来用于组件的完整道具接口,但只使用可选道具来设置默认道具:

import * as React from "react";


// Required props
interface IMyComponentRequiredProps {
title: string;
}


// Optional props
interface IMyComponentOptionalProps {
color: string;
fontSize: number;
}


// Combine required and optional props to build the full prop interface
interface IMyComponentProps
extends IMyComponentRequiredProps,
IMyComponentOptionalProps {}


// Use the optional prop interface to define the default props
const defaultProps: IMyComponentOptionalProps = {
color: "red",
fontSize: 40,
};


// Use the full props within the actual component
const MyComponent = (props: IMyComponentProps) => {
const { title, color, fontSize } = props;
return <h1 style=\{\{ color, fontSize }}>{title}</h1>;
};


// Be sure to set the default props
MyComponent.defaultProps = defaultProps;


export default MyComponent;

我可能错了,但是在第二次投票的回复中传递一个默认的道具值可能会导致细微的错误或者过度执行 useeffect (我没有足够的代表来回复这里,所以 这是是一个可重现的代码盒)

即使它是一个真正人为的例子,并且可能在大多数情况下只是糟糕的组件设计,我也不止一次地看到这种情况,甚至打破了整个页面。

2022年最新情况

对于函数组件,确实存在 defaultProps字段的 可能的贬值。我不相信这会很快发生,因为它已经写了大量的代码,但一个警告显示在控制台是非常可能的。

我正在使用下面的解决方案,它提供了正确的行为和正确的 TypeScript 验证。它适用于混合定义/未定义的属性,也适用于有/无默认值的属性——也就是说,它涵盖了所有情况:

interface Props {
name: string;
surname?: string;
age?: number;
}


const defaultProps = {
surname: 'Doe',
};


function MyComponent(propsIn: Props) {
const props = {...defaultProps, ...propsIn};


return <div>{props.surname}</div>;
}

而且 VSCode 自动补全功能非常准确:

VSCode autocomplete

它已经用 TypeScript 4.7进行了测试。