Typescript: 默认道具在功能组件中不起作用

创建于 2019-05-04  ·  16评论  ·  资料来源: microsoft/TypeScript

TypeScript版本: 3.4.5

搜索词:
反应默认道具defaultProps功能组件无状态

import React from "react";

interface Props {
  name: string;
  optional: string;
}

const Component = ({ name, optional = "default" }: Props) => (
  <p>{name + " " + optional}</p>
);

const Test = () => <Component name="test" />;

预期行为:
按照打字稿3.0发行说明中, optional道具不应该需要Test ,因为它已经有一个默认情况下使用ES2015默认初始化的功能被定义Component

实际行为:
引发以下编译错误:

类型'{name:string;类型中缺少属性'optional'。 }”,但在“道具”类型中为必填项。

游乐场链接:
链接
看起来游乐场不支持TSX。

相关问题:

27425

Question

最有用的评论

使用TypeScript 3.1或更高版本,您应该能够编写:

export interface Props {
    name: string;
}

function Greet(props: Props) {
    return <div>Hello {props.name.toUpperCase()}!</div>;
}
Greet.defaultProps = {
  name: "world",
} as Partial<Props>; // Good practice, without it you could use a number as default prop and TypeScript wouldn't complain…

const component = <Greet />; // no errors

所有16条评论

文档可能不清楚,但是您必须在Props接口中将该属性标记为可选:

interface Props {
    name: string;
    optional?: string;
}

这似乎与发行说明所说的不符:

export interface Props {
    name: string;
}

// ...

function Greet({ name = "world" }: Props) {
    return <div>Hello {name.toUpperCase()}!</div>;
}

将prop设置为可选还意味着,当您在组件外部(在测试中)访问props时,类型系统不保证prop存在,即使它始终存在。

例:

const wrapper = shallow(<Test/>);

// optional is string | undefined instead of string
const optional = wrapper
        .find(Component)
        .props()
        .optional;

如果optional是一个函数,则必须在执行前检查它是否存在。 例如,如果您提供一个默认的onClick道具,它仅调用preventDefault

使用TypeScript 3.1或更高版本,您应该能够编写:

export interface Props {
    name: string;
}

function Greet(props: Props) {
    return <div>Hello {props.name.toUpperCase()}!</div>;
}
Greet.defaultProps = {
  name: "world",
} as Partial<Props>; // Good practice, without it you could use a number as default prop and TypeScript wouldn't complain…

const component = <Greet />; // no errors

使用默认初始化器功能不适用于默认道具是否是一个错误? 鉴于发行说明中提供的示例不适用于最新的TypeScript版本,这似乎是一种回归。

@tbassetto的问题是TS不会强迫您实际提供默认值:

import React from 'react';

interface Props {
  myProp: string;
}

const Comp = (props: Props) => {
  return (
    <div>
      {props.myProp.toUpperCase()}
    </div>
  );
};

Comp.defaultProps = {

} as Pick<Props, 'myProp'>;

const comp = <Comp />;

另一个烦人的事情是您必须首先执行以下操作:如果我键入Comp作为React.FC<Props> ,则可以很好地键入defaultProps ,但是会出现其他问题。

总而言之,TypeScripts JSX / React支持现在似乎处于一种奇怪的“不完美”状态,但是运行起来似乎一切都很好(至少在我看来-主要是,我似乎找不到任何可靠的注释了目前在3.4.5中以一种类型安全的方式来执行无状态React组件的“官方”方式)。

尽管我看到每个人都引用了变通方法,但是我无法让他们中的任何一个工作。

我正在使用3.3.3版本

export interface Props {
  shouldTruncateContent: boolean;
}

const Alert: React.FunctionComponent<Props> = ({
  children,
  shouldTruncateContent = false
}) => {
  return (
        <S.Content shouldTruncateContent={shouldTruncateContent} size="fill">
          {children}
        </S.Content>
  );
};

Alert.defaultProps = {
  shouldTruncateContent: false
} as Pick<Props, 'shouldTruncateContent'>;

export default Alert;

有谁对为什么这仍然引发错误有任何见解

TS2741: Property 'shouldTruncateContent' is missing in type '{ children: string; }' but required in type 'Props'.

我也尝试了#27425和#519中提出的所有修补程序。

@tomspeak无论是我的解决办法@Hotellworaround (虽然这一个使所有道具可选)。 使用示例代码在3.5上进行了测试。

尽管我看到每个人都引用了变通方法,但是我无法让他们中的任何一个工作。

我正在使用3.3.3版本

export interface Props {
  shouldTruncateContent: boolean;
}

const Alert: React.FunctionComponent<Props> = ({
  children,
  shouldTruncateContent = false
}) => {
  return (
        <S.Content shouldTruncateContent={shouldTruncateContent} size="fill">
          {children}
        </S.Content>
  );
};

Alert.defaultProps = {
  shouldTruncateContent: false
} as Pick<Props, 'shouldTruncateContent'>;

export default Alert;

有谁对为什么这仍然引发错误有任何见解

TS2741: Property 'shouldTruncateContent' is missing in type '{ children: string; }' but required in type 'Props'.

我也尝试了#27425和#519中提出的所有修补程序。

您只需要使shouldTruncateContent:boolean; 可选的shouldTruncateContent?: boolean;

文档可能不清楚,但是您必须在Props接口中将该属性标记为可选:

interface Props {
    name: string;
    optional?: string;
}

我在各处都使用此可选类型。 为什么要投反对票? 有人可以解释吗?

@ralexhassle ,我无法解释反对票,但我可以解释那肯定是键入组件的optional属性的正确方法。
您可能更喜欢使用defaultProps ,这个问题的示例未使用它,但是就我而言,将可选属性标记为optional可能非常好...

问题的目的是道具不是可选的,而是具有默认值的(因此在使用组件时可以省略)。 如果使用?将prop标记为可选,则TS会认为它可能是未定义的,并迫使您处理这种情况。 但是,由于存在默认值,因此永远不会被不确定。 降低投票率是因为评论员似乎不了解该问题,并提出了与3.0版本说明矛盾的内容。

@RyanCavanaugh僵尸

也许我错过了,但是尽管有很多解决方法,但我看不到实际的答案?

PS:使用TypeScript v4

您可以通过这种方式进行操作,此处“道具”中的属性是可选参数,并在组件中进一步使用。

interface Props {
  children: ReactNode;
  properties?: Record<string, unknown>;
}

const defaultProps: Props = {
  children: '',
  properties: {
    marginTop: 32,
    marginLeft: 0,
    marginBottom: 8,
    marginRight: 0,
  },
};

const RadioListLabel: React.FC<Props> = ({
  children,
  properties = defaultProps.properties,
}) => (
  <View
    margin={[
properties ? properties.marginTop : 0
        properties ? properties.marginLeft : 0
        properties ? properties.marginBottom : 0
        properties ? properties.marginRight : 0
      ]}
  >
    <Text size="m" variant="heading2" lineHeight="body">
      {children}
    </Text>
  </View>
  )

@lakhmeranikita此问题的目的是避免将prop类型标记为可选。

我无法获取函数默认参数或其他建议以正确进行类型检查。 我能够找到的唯一可行的解​​决方案是:

import React from "react";

type DefaultProps = { optionalProp: number };
type Props = {
  requiredProp: "some_string" | "other_string";
} & DefaultProps;

export const BaseComponent = (props: Props) => {
  const { requiredProp, optionalProp } = props;
  return (
    <div>
      {requiredProp} {optionalProp}
    </div>
  );
};

BaseComponent.defaultProps = {
  optionalProp: 0,
} as Partial<DefaultProps>;

const comp = <BaseComponent requiredProp="some_string" />;

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

Antony-Jones picture Antony-Jones  ·  3评论

wmaurer picture wmaurer  ·  3评论

jbondc picture jbondc  ·  3评论

DanielRosenwasser picture DanielRosenwasser  ·  3评论

fwanicka picture fwanicka  ·  3评论