Версия TypeScript: 3.4.5
Условия поиска:
реагировать по умолчанию props 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" />;
Ожидаемое поведение:
Согласно примечаниям к выпуску TypeScript 3.0, свойство optional
не должно требоваться в Test
поскольку оно было определено по умолчанию с использованием функции инициализаторов по умолчанию ES2015 в Component
.
Фактическое поведение:
Выдается следующая ошибка компиляции:
Свойство 'optional' отсутствует в типе '{name: string; } ', но требуется в типе' Props '.
Ссылка на игровую площадку:
Ссылка
Не похоже, что игровая площадка поддерживает TSX.
Связанные вопросы:
В документации это может быть неясно, но вы должны пометить свойство как необязательное в вашем интерфейсе Props
:
interface Props {
name: string;
optional?: string;
}
Похоже, это не соответствует тому, что говорится в примечаниях к выпуску:
export interface Props {
name: string;
}
// ...
function Greet({ name = "world" }: Props) {
return <div>Hello {name.toUpperCase()}!</div>;
}
Сделать опору необязательной также означает, что при доступе к реквизитам вне компонента (в тесте) система типов не гарантирует, что пропс существует, даже если он будет существовать всегда.
Пример:
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 сейчас, кажется, находится в странном, не совсем идеальном состоянии, но работает так, как будто все в порядке (по крайней мере, на мой взгляд - в основном, я не могу найти твердого примечания о том, что в настоящее время является «официальным» способом создания компонентов React без сохранения состояния типобезопасным способом для 3.4.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.
@tomspeak Либо мой обходной путь, либо woraround от @Hotell (хотя здесь все реквизиты
Хотя я вижу, что все ссылаются на обходные пути, я не могу заставить их работать.
Я на версии 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 , я не могу объяснить
Вы можете предпочесть использовать defaultProps
, который в примере вопроса не используется, но, насколько я понимаю, отметка необязательных свойств как необязательных, вероятно, совершенно нормально ...
Цель проблемы в том, что реквизиты не являются необязательными, но имеют значение по умолчанию (поэтому их можно избежать при использовании компонента). Если вы пометите опору как необязательную с помощью ?
тогда TS предполагает, что она может быть неопределенной, и заставит вас обработать этот случай. Однако он никогда не будет неопределенным, потому что есть значение по умолчанию. Голосование против связано с тем, что комментатор, похоже, не понял проблему и предложил что-то, что противоречило примечаниям к версии 3.0.
@RyanCavanaugh, почему бот закрыл эту проблему?
Возможно, я пропустил это, но я не вижу фактического ответа, несмотря на множество обходных путей?
PS: с использованием TypeScript v4
Вы можете сделать это таким образом, здесь свойства в Props являются необязательным параметром и в дальнейшем используются в компоненте.
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 Цель этой проблемы - избежать пометки типа опоры как необязательного.
Мне не удалось получить аргументы функции по умолчанию или другие предложения для правильной проверки типа. Единственное работоспособное решение, которое мне удалось найти, это следующее:
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" />;
Самый полезный комментарий
С TypeScript 3.1 или выше вы должны уметь писать: