Я не могу понять, как установить значения свойств по умолчанию для моих компонентов с помощью 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, которые использует моя компания, полагаются на них и не используют их, не являются выбором.
Использование static defaultProps
является правильным. Вы также должны использовать интерфейсы, а не классы, для реквизита и состояния.
Обновление 2018/12/1: TypeScript улучшил проверку типов, связанную с defaultProps
течением времени. Продолжайте читать для последнего и самого лучшего использования вплоть до старых обычаев и проблем.
В 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 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
будет possibly undefined
и потребует ненулевого утверждения (т.е. this.props.foo!
) Или type-guard (т. if (this.props.foo)...
) для удалить undefined
. Это раздражает, так как значение prop по умолчанию означает, что оно фактически никогда не будет неопределенным, но TS не понимает этот поток. Это одна из главных причин, по которой в TS 3.0 добавлена явная поддержка defaultProps
. Это работает так же, но у вас нет Partial
типов, поэтому просто опустите Partial<>
и либо предоставьте значения по умолчанию для всех необходимых реквизитов (даже если эти значения по умолчанию никогда не будут использоваться), либо полностью пропустите явную аннотацию типа.
Вы также можете использовать defaultProps
для компонентов функций, но вам нужно ввести свою функцию в интерфейс StatelessComponent
(FunctionComponent
в @types/react
версию 16.7.2
+), чтобы TypeScript знал о defaultProps
для функции:
interface PageProps {
foo?: string;
bar: number;
}
const PageComponent: StatelessComponent<PageProps> = (props) => {
return (
<span>Hello, {props.foo}, {props.bar}</span>
);
};
PageComponent.defaultProps = {
foo: "default"
};
Обратите внимание, что вам не нужно нигде использовать Partial<PageProps>
потому что StatelessComponent.defaultProps
уже определено как частичное в TS 2. 1+.
Другая хорошая альтернатива (это то, что я использую) - это деструктурировать параметры вашего props
и напрямую назначить значения по умолчанию:
const PageComponent: StatelessComponent<PageProps> = ({foo = "default", bar}) => {
return (
<span>Hello, {foo}, {bar}</span>
);
};
Тогда вам не нужны defaultProps
! Имейте в виду, что если вы предоставите defaultProps
для компонента функции, он будет иметь приоритет над значениями параметров по умолчанию, поскольку React всегда будет явно передавать значения defaultProps
(поэтому параметры никогда не определяются, поэтому параметр по умолчанию никогда не используется.) Итак, вы ' буду использовать один или другой, а не оба.
<PageComponent>
где-то без пропуска foo
prop. Вы можете сделать это необязательным, используя foo?: string
в вашем интерфейсе.
С Typescript 2.1+ используйте Partial <T> вместо того, чтобы сделать ваши свойства интерфейса необязательными.
export interface Props {
obj: Model,
a: boolean
b: boolean
}
public static defaultProps: Partial<Props> = {
a: true
};
С TypScript 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.6
. Он работает с 16.4.11
.
export interface Props { name?: string;}
где имя - это дополнительная опора? Я продолжаю получать TS2532 Object is possibly 'undefined'
undefined
является своего рода автоматическим значением по умолчанию для этих реквизитов. Вы хотите иметь возможность передавать undefined
как явное значение иногда, но есть другое значение по умолчанию? Вы пробовали export interface Props {name: string | undefined;}
вместо? Я не пробовал это, просто идея.
Из комментария @pamelus о принятом ответе:
Вам либо нужно сделать все свойства интерфейса необязательными (плохими), либо укажите значение по умолчанию также для всех обязательных полей (ненужных шаблон) или не указывать тип в файлах defaultProps.
На самом деле вы можете использовать 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"
};
Для тех, у кого есть дополнительные реквизиты, которым нужны значения по умолчанию. Кредит здесь :)
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>
)
}
}
static defaultProps
является правильным. Вы можете опубликовать этот код?