使用 TypeScript 的 React 组件中的默认属性值 [英] Default property value in React component using TypeScript

查看:114
本文介绍了使用 TypeScript 的 React 组件中的默认属性值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道如何使用 Typescript 为我的组件设置默认属性值.

I can't figure out how to set default property values for my components using Typescript.

这是源代码:

class PageState
{
}

export class PageProps
{
    foo: string = "bar";
}

export class PageComponent extends React.Component<PageProps, PageState>
{
    public render(): JSX.Element
    {
        return (
            <span>Hello, world</span>
        );
    }
}

当我尝试像这样使用组件时:

And when I try to use the component like this:

ReactDOM.render(<PageComponent />, document.getElementById("page"));

我收到一条错误消息,指出缺少 foo 属性.我想使用默认值.我还尝试在组件内部使用 static defaultProps = ... ,但它没有我怀疑的效果.

I get an error saying property foo is missing. I want to use the default value. I've also tried to use static defaultProps = ... inside the component, but it had no effect as I suspected.

src/typescript/main.tsx(8,17): error TS2324: Property 'foo' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<PageComponent> & PageProps & { children?: ReactEle...'.

如何使用默认属性值?我公司使用的很多 JS 组件都依赖于它们,不使用它们不是一种选择.

How can I use default property values? Many JS components my company uses rely on them and not using them is not a choice.

推荐答案

类组件的默认 props

使用 static defaultProps 是正确的.您还应该为 props 和 state 使用接口,而不是类.

Default props with class component

Using static defaultProps is correct. You should also be using interfaces, not classes, for the props and state.

2018/12/1 更新:随着时间的推移,TypeScript 改进了与 defaultProps 相关的类型检查.继续阅读以了解最新和最常用的用法以及较旧的用法和问题.

Update 2018/12/1: TypeScript has improved the type-checking related to defaultProps over time. Read on for latest and greatest usage down to older usages and issues.

TypeScript 专门 添加了对 defaultProps 的支持,以使类型检查按您期望的方式工作.示例:

TypeScript specifically added support for defaultProps to make type-checking work how you'd expect. Example:

interface PageProps {
  foo: string;
  bar: string;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, { this.props.foo.toUpperCase() }</span>
        );
    }
}

可以在不传递 foo 属性的情况下呈现和编译:

Which can be rendered and compile without passing a foo attribute:

<PageComponent bar={ "hello" } />

注意:

  • foonot 标记为可选的(即 foo?: string),即使它不是 JSX 属性所必需的.标记为可选意味着它可以是 undefined,但实际上它永远不会是 undefined,因为 defaultProps 提供了一个默认值.想想它类似于 您可以将函数参数标记为可选,或使用默认值,但不能同时使用两者,但这都意味着调用不需要指定值.TypeScript 3.0+ 以类似的方式对待 defaultProps,这对 React 用户来说真的很酷!
  • defaultProps 没有明确的类型注释.它的类型由编译器推断和使用,以确定需要哪些 JSX 属性.您可以使用 defaultProps: Pick 来确保 defaultProps 匹配 PageProps 的子集.关于这个警告的更多信息是 在这里解释.
  • 这需要 @types/react 版本 16.4.11 才能正常工作.
  • foo is not marked optional (ie foo?: string) even though it's not required as a JSX attribute. Marking as optional would mean that it could be undefined, but in fact it never will be undefined because defaultProps provides a default value. Think of it similar to how you can mark a function parameter optional, or with a default value, but not both, yet both mean the call doesn't need to specify a value. TypeScript 3.0+ treats defaultProps in a similar way, which is really cool for React users!
  • The defaultProps has no explicit type annotation. Its type is inferred and used by the compiler to determine which JSX attributes are required. You could use defaultProps: Pick<PageProps, "foo"> to ensure defaultProps matches a sub-set of PageProps. More on this caveat is explained here.
  • This requires @types/react version 16.4.11 to work properly.

在 TypeScript 3.0 实现对 defaultProps 的编译器支持之前,您仍然可以使用它,并且它在运行时 100% 与 React 一起工作,但是由于 TypeScript 在检查 JSX 属性时只考虑了道具必须使用 ? 将具有默认值的道具标记为可选.示例:

Before TypeScript 3.0 implemented compiler support for defaultProps you could still make use of it, and it worked 100% with React at runtime, but since TypeScript only considered props when checking for JSX attributes you'd have to mark props that have defaults as optional with ?. Example:

interface PageProps {
    foo?: string;
    bar: number;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps: Partial<PageProps> = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, world</span>
        );
    }
}

注意:

  • Partial<> 注释 defaultProps 是个好主意,以便它根据您的道具进行类型检查,但您不必提供所有必需的属性使用默认值,这是没有意义的,因为必需的属性永远不需要默认值.
  • 当使用 strictNullChecks 时,this.props.foo 的值将是 可能未定义 并且需要一个非空断言(即 this.props.foo!) 或类型保护(即 if (this.props.foo) ...) 删除 undefined.这很烦人,因为默认的 prop 值意味着它实际上永远不会是未定义的,但是 TS 不理解这个流程.这是 TS 3.0 明确支持 defaultProps 的主要原因之一.
  • It's a good idea to annotate defaultProps with Partial<> so that it type-checks against your props, but you don't have to supply every required property with a default value, which makes no sense since required properties should never need a default.
  • When using strictNullChecks the value of this.props.foo will be possibly undefined and require a non-null assertion (ie this.props.foo!) or type-guard (ie if (this.props.foo) ...) to remove undefined. This is annoying since the default prop value means it actually will never be undefined, but TS didn't understand this flow. That's one of the main reasons TS 3.0 added explicit support for defaultProps.

这工作相同,但您没有 Partial 类型,因此只需省略 Partial<> 并为所有必需的道具提供默认值(即使那些永远不会使用默认值)或完全省略显式类型注释.

This works the same but you don't have Partial types, so just omit Partial<> and either supply default values for all required props (even though those defaults will never be used) or omit the explicit type annotation completely.

你也可以在函数组件上使用 defaultProps,但是你必须将你的函数输入到 FunctionComponent(StatelessComponent in 版本 16.7.2 之前的 @types/react) 接口,以便 TypeScript 知道函数上的 defaultProps:

You can use defaultProps on function components as well, but you have to type your function to the FunctionComponent (StatelessComponent in @types/react before version 16.7.2) interface so that TypeScript knows about defaultProps on the function:

interface PageProps {
  foo?: string;
  bar: number;
}

const PageComponent: FunctionComponent<PageProps> = (props) => {
  return (
    <span>Hello, {props.foo}, {props.bar}</span>
  );
};

PageComponent.defaultProps = {
  foo: "default"
};

请注意,您不必在任何地方使用 Partial,因为 FunctionComponent.defaultProps 已在 TS 2.1+ 中指定为部分.

Note that you don't have to use Partial<PageProps> anywhere because FunctionComponent.defaultProps is already specified as a partial in TS 2.1+.

另一个不错的选择(这是我使用的)是解构您的 props 参数并直接分配默认值:

Another nice alternative (this is what I use) is to destructure your props parameters and assign default values directly:

const PageComponent: FunctionComponent<PageProps> = ({foo = "default", bar}) => {
  return (
    <span>Hello, {foo}, {bar}</span>
  );
};

那么你根本不需要defaultProps!请注意,如果您在函数组件上do提供 defaultProps,它将优先于默认参数值,因为 React 将始终显式传递 defaultProps值(因此参数永远不会未定义,因此永远不会使用默认参数.)所以您可以使用其中一个,而不是同时使用.

Then you don't need the defaultProps at all! Be aware that if you do provide defaultProps on a function component it will take precedence over default parameter values, because React will always explicitly pass the defaultProps values (so the parameters are never undefined, thus the default parameter is never used.) So you'd use one or the other, not both.

这篇关于使用 TypeScript 的 React 组件中的默认属性值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆