Я не могу понять, как установить значения свойств по умолчанию для моих компонентов с помощью 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>
);
}
}
И когда я пытаюсь использовать компонент вот так:
ReactDOM.render(<PageComponent />, document.getElementById("page"));
Я получаю сообщение об foo
отсутствии свойства . Я хочу использовать значение по умолчанию. Я также пытался использовать static defaultProps = ...
внутри компонента, но это не дало результата, как я подозревал.
src/typescript/main.tsx(8,17): error TS2324: Property 'foo' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<PageComponent> & PageProps & { children?: ReactEle...'.
Как я могу использовать значения свойств по умолчанию? Многие компоненты JS, которые использует моя компания, полагаются на них, и отказ от них не является выбором.
reactjs
typescript
tsx
Том
источник
источник
static defaultProps
правильно. Вы можете опубликовать этот код?Ответы:
Свойства по умолчанию с компонентом класса
Использование
static defaultProps
правильно. Вы также должны использовать интерфейсы, а не классы, для свойств и состояния.Обновление 2018/12/1 : TypeScript
defaultProps
со временем улучшил проверку типов . Читайте, чтобы узнать о последних и наиболее эффективных способах использования, вплоть до более старых способов использования и проблем.Для TypeScript 3.0 и выше
TypeScript специально добавил поддержку,
defaultProps
чтобы проверка типов работала так, как вы ожидаете. Пример: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
атрибута:<PageComponent bar={ "hello" } />
Обратите внимание, что:
foo
это не отмечен факультативным (то естьfoo?: string
) , даже если это не требуется в качестве атрибута JSX. Пометка как необязательная будет означать, что это может бытьundefined
, но на самом деле этого никогда не будет,undefined
потому чтоdefaultProps
предоставляется значение по умолчанию. Думайте об этом аналогично тому, как вы можете пометить параметр функции как необязательный или со значением по умолчанию, но не обоими сразу, но оба они означают, что при вызове не нужно указывать значение . TypeScript 3.0+defaultProps
работает аналогично, что действительно здорово для пользователей React!defaultProps
имеет явной аннотации типа. Его тип определяется и используется компилятором, чтобы определить, какие атрибуты JSX требуются. Вы можете использоватьdefaultProps: Pick<PageProps, "foo">
для обеспеченияdefaultProps
совпадений подмножествоPageProps
. Подробнее об этом предупреждении рассказывается здесь .@types/react
версия16.4.11
.Для TypeScript с 2.1 по 3.0
До того, как TypeScript 3.0 реализовал поддержку компилятора,
defaultProps
вы все еще могли его использовать, и он работал на 100% с React во время выполнения, но поскольку TypeScript учитывал только реквизиты при проверке атрибутов JSX, вам нужно было бы пометить реквизиты, которые имеют значения по умолчанию, как необязательные?
. Пример: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> ); } }
Обратите внимание, что:
defaultProps
сPartial<>
так , что его типом проверок в отношении вашего реквизита, но вы не должны предоставлять все требуемое свойство со значением по умолчанию, что не имеет смысла , так как требуемые свойства никогда не должны по умолчанию.strictNullChecks
значенияthis.props.foo
will будетpossibly undefined
и потребуется удаление ненулевого утверждения (т.е.this.props.foo!
) или защиты типа (т.е.if (this.props.foo) ...
)undefined
. Это раздражает, поскольку значение свойства по умолчанию означает, что оно никогда не будет неопределенным, но TS не понимает этот поток. Это одна из основных причин, по которой в TS 3.0 была добавлена явная поддержкаdefaultProps
.До TypeScript 2.1
Это работает так же, но у вас нет
Partial
типов, поэтому просто опуститеPartial<>
и либо укажите значения по умолчанию для всех необходимых реквизитов (даже если эти значения по умолчанию никогда не будут использоваться), либо полностью опустите явную аннотацию типа.Свойства по умолчанию с функциональными компонентами
Вы также можете использовать
defaultProps
компоненты функций, но вы должны ввести свою функцию в интерфейсFunctionComponent
(StatelessComponent
в более@types/react
ранней версии16.7.2
), чтобы TypeScript знал оdefaultProps
функции:interface PageProps { foo?: string; bar: number; } const PageComponent: FunctionComponent<PageProps> = (props) => { return ( <span>Hello, {props.foo}, {props.bar}</span> ); }; PageComponent.defaultProps = { foo: "default" };
Обратите внимание, что вам не нужно
Partial<PageProps>
нигде использовать, потому чтоFunctionComponent.defaultProps
это уже указано как частичное в TS 2.1+.Еще одна хорошая альтернатива (это то, что я использую) - это деструктурировать ваши
props
параметры и напрямую присвоить значения по умолчанию:const PageComponent: FunctionComponent<PageProps> = ({foo = "default", bar}) => { return ( <span>Hello, {foo}, {bar}</span> ); };
Тогда вам это вообще не нужно
defaultProps
! Имейте в виду , что если вы действительно обеспечиваютdefaultProps
на функции компонента будет иметь приоритет над значениями параметров по умолчанию, потому что React будет всегда явно передатьdefaultProps
значения (поэтому параметры никогда не определено, что параметр по умолчанию никогда не используется.) Таким образом , вы будете использовать один или другой, но не оба.источник
<PageComponent>
где-то используете, не передавfoo
опору. Вы можете сделать это необязательным, используяfoo?: string
в своем интерфейсе.public static defaultProps
илиstatic defaultProps
(public
по умолчанию), чтобы все (компилятор и среда выполнения React) работало правильно. Он может работать во время выполненияprivate static defaultProps
только потому, чтоprivate
иpublic
не существует во время выполнения, но компилятор не будет работать правильно.В Typescript 2.1+ используйте Partial <T> вместо того, чтобы делать свойства интерфейса необязательными.
export interface Props { obj: Model, a: boolean b: boolean } public static defaultProps: Partial<Props> = { a: true };
источник
В Typescript 3.0 есть новое решение этой проблемы:
export interface Props { name: string; } export class Greet extends React.Component<Props> { render() { const { name } = this.props; return <div>Hello ${name.toUpperCase()}!</div>; } static defaultProps = { name: "world"}; } // Type-checks! No type assertions needed! let el = <Greet />
Обратите внимание, что для этого вам нужна более новая версия,
@types/react
чем16.4.6
. Работает с16.4.11
.источник
export interface Props { name?: string;}
где имя - необязательная опора? Я продолжаю получатьTS2532 Object is possibly 'undefined'
undefined
это своего рода автоматическое значение по умолчанию для этих реквизитов. Вы хотите иметь возможностьundefined
иногда передавать в качестве явного значения, но иметь другое значение по умолчанию? Вы пробовалиexport interface Props {name: string | undefined;}
вместо этого? Не пробовал, просто идея.?
аналогично добавлению|undefined
. Я хочу, при желании, передать опору и позволитьdefaultProps
обработать этот случай. Похоже, что в TS3 это пока невозможно. Я просто использовать страшилисьname!
синтаксис , так как я знаю , что никогда ,undefined
когдаdefaultProps
установлены. В любом случае спасибо!Для тех, у кого есть дополнительные реквизиты, которым нужны значения по умолчанию. Кредит здесь :)
interface Props { firstName: string; lastName?: string; } interface DefaultProps { lastName: string; } type PropsWithDefaults = Props & DefaultProps; export class User extends React.Component<Props> { public static defaultProps: DefaultProps = { lastName: 'None', } public render () { const { firstName, lastName } = this.props as PropsWithDefaults; return ( <div>{firstName} {lastName}</div> ) } }
источник
Что касается функционального компонента, я бы предпочел сохранить
props
аргумент, поэтому вот мое решение:interface Props { foo: string; bar?: number; } // IMPORTANT!, defaultProps is of type {bar: number} rather than Partial<Props>! const defaultProps = { bar: 1 } // externalProps is of type Props const FooComponent = exposedProps => { // props works like type Required<Props> now! const props = Object.assign(defaultProps, exposedProps); return ... } FooComponent.defaultProps = defaultProps;
источник
Из комментария @pamelus к принятому ответу:
На самом деле вы можете использовать наследование интерфейса Typescript . Результирующий код стал немного более подробным.
interface OptionalGoogleAdsProps { format?: string; className?: string; style?: any; scriptSrc?: string } interface GoogleAdsProps extends OptionalGoogleAdsProps { client: string; slot: string; } /** * Inspired by https://github.com/wonism/react-google-ads/blob/master/src/google-ads.js */ export default class GoogleAds extends React.Component<GoogleAdsProps, void> { public static defaultProps: OptionalGoogleAdsProps = { format: "auto", style: { display: 'block' }, scriptSrc: "//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" };
источник
Функциональный компонент
Собственно, для функционального компонента лучшая практика такая, как показано ниже, я создаю образец компонента Spinner:
import React from 'react'; import { ActivityIndicator } from 'react-native'; import { colors } from 'helpers/theme'; import type { FC } from 'types'; interface SpinnerProps { color?: string; size?: 'small' | 'large' | 1 | 0; animating?: boolean; hidesWhenStopped?: boolean; } const Spinner: FC<SpinnerProps> = ({ color, size, animating, hidesWhenStopped, }) => ( <ActivityIndicator color={color} size={size} animating={animating} hidesWhenStopped={hidesWhenStopped} /> ); Spinner.defaultProps = { animating: true, color: colors.primary, hidesWhenStopped: true, size: 'small', }; export default Spinner;
источник