Skip to content

Commit

Permalink
fix: remove injectIntl types from component props (#1415)
Browse files Browse the repository at this point in the history
* fix: remove unused WrappedComponentProps type

* refactor: don't use HOC for formatted component factory

* refactor: simplify types interface

* refactor: simplify code

* refactor: simplify code

* refactor: keep using React.FC

* refactor: to use enum for DisplayName options

fixes #1414
  • Loading branch information
emmenko authored and longlho committed Aug 13, 2019
1 parent a18c74a commit 9b359ec
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 54 deletions.
77 changes: 38 additions & 39 deletions src/components/createFormattedComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
import * as React from 'react';
import {invariantIntlContext} from '../utils';
import {IntlShape, FormatDateOptions, FormatNumberOptions} from '../types';
import withIntl, {WrappedComponentProps} from './injectIntl';
import {Context} from './injectIntl';

export default function createFormattedComponent<
T extends 'formatDate' | 'formatTime' | 'formatNumber'
>(type: T) {
type FormatOptions<T> = T extends 'formatDate'
? FormatDateOptions
: T extends 'formatTime'
? FormatDateOptions
: FormatNumberOptions;
type FormatFn = IntlShape[T];
type Props = FormatOptions<T> &
WrappedComponentProps & {
value: Parameters<FormatFn>[0];
children?(val: string): React.ReactElement | null;
};
const Component: React.FC<Props> = props => {
const {
value,
children,
intl: {[type]: formatFn, textComponent: Text},
} = props;
enum DisplayName {
formatDate = 'FormattedDate',
formatTime = 'FormattedTime',
formatNumber = 'FormattedNumber',
}

let formattedValue = formatFn(value as any, props);
type Formatter = {
formatDate: FormatDateOptions;
formatTime: FormatDateOptions;
formatNumber: FormatNumberOptions;
};

if (typeof children === 'function') {
return children(formattedValue);
}
if (Text) {
return <Text>{formattedValue}</Text>;
}
// Work around @types/react where React.FC cannot return string
return formattedValue as any;
};
Component.displayName =
type === 'formatDate'
? 'FormattedDate'
: type === 'formatTime'
? 'FormattedTime'
: 'FormattedNumber';
return {
Component: withIntl(Component),
export default function createFormattedComponent<Name extends keyof Formatter>(
name: Name
) {
type Options = Formatter[Name];
type FormatFn = IntlShape[Name];
type Props = Options & {
value: Parameters<FormatFn>[0];
children?: (val: string) => React.ReactElement | null;
};

const Component: React.FC<Props> = props => (
<Context.Consumer>
{intl => {
invariantIntlContext(intl);

const formattedValue = intl[name](props.value as any, props);

if (typeof props.children === 'function') {
return props.children(formattedValue);
}
const Text = intl.textComponent || React.Fragment;
return <Text>{formattedValue}</Text>;
}}
</Context.Consumer>
);
Component.displayName = DisplayName[name];
return Component;
}
4 changes: 2 additions & 2 deletions src/components/message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import * as React from 'react';
import {PrimitiveType, FormatXMLElementFn} from 'intl-messageformat';
import {Context, WrappedComponentProps} from './injectIntl';
import {Context} from './injectIntl';
import {MessageDescriptor} from '../types';
import {formatMessage as baseFormatMessage} from '../format';
import {
Expand Down Expand Up @@ -42,7 +42,7 @@ const defaultFormatMessage = (

export interface Props<
V extends Record<string, any> = Record<string, React.ReactNode>
> extends MessageDescriptor, WrappedComponentProps {
> extends MessageDescriptor {
values?: V;
tagName?: React.ElementType<any>;
children?(...nodes: React.ReactNodeArray): React.ReactNode;
Expand Down
6 changes: 2 additions & 4 deletions src/components/relative.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import * as React from 'react';
import {Context, WrappedComponentProps} from './injectIntl';
import {Context} from './injectIntl';
import {FormatRelativeTimeOptions} from '../types';
import {Unit} from '@formatjs/intl-relativetimeformat';
import * as invariant_ from 'invariant';
Expand Down Expand Up @@ -60,9 +60,7 @@ function valueToSeconds(value?: number, unit?: Unit): number {
}
}

export interface Props
extends FormatRelativeTimeOptions,
WrappedComponentProps {
export interface Props extends FormatRelativeTimeOptions {
value?: number;
unit?: Unit;
updateIntervalInSeconds?: number;
Expand Down
12 changes: 3 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,9 @@ export {
} from './components/injectIntl';
export {default as useIntl} from './components/useIntl';
export {default as IntlProvider, createIntl} from './components/provider';
export const {Component: FormattedDate} = createFormattedComponent(
'formatDate'
);
export const {Component: FormattedTime} = createFormattedComponent(
'formatTime'
);
export const {Component: FormattedNumber} = createFormattedComponent(
'formatNumber'
);
export const FormattedDate = createFormattedComponent('formatDate');
export const FormattedTime = createFormattedComponent('formatTime');
export const FormattedNumber = createFormattedComponent('formatNumber');
export {default as FormattedRelativeTime} from './components/relative';
export {default as FormattedPlural} from './components/plural';
export {default as FormattedMessage} from './components/message';
Expand Down

0 comments on commit 9b359ec

Please sign in to comment.