Skip to content

Commit 2030bdd

Browse files
committed
fix: type definitions and make behavior match spec more
1 parent 3bd63b4 commit 2030bdd

File tree

8 files changed

+62
-77
lines changed

8 files changed

+62
-77
lines changed

src/components/html-message.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,4 @@ class FormattedHTMLMessage extends BaseFormattedMessage<PrimitiveType> {
4747
}
4848
}
4949

50-
export const BaseFormattedHTMLMessage = FormattedHTMLMessage; // testing purpose only
51-
5250
export default withIntl(FormattedHTMLMessage);

src/components/injectIntl.tsx

+18-21
Original file line numberDiff line numberDiff line change
@@ -47,28 +47,25 @@ export default function injectIntl<
4747

4848
const WithIntl: React.FC<P & {forwardedRef?: React.Ref<any>}> & {
4949
WrappedComponent: typeof WrappedComponent;
50-
} = props => {
51-
return (
52-
<IntlConsumer>
53-
{intl => {
54-
if (enforceContext) {
55-
invariantIntlContext({intl});
56-
}
57-
58-
return (
59-
<WrappedComponent
60-
{...props}
61-
{...{
62-
[intlPropName]: intl,
63-
}}
64-
ref={forwardRef ? props.forwardedRef : null}
65-
/>
66-
);
67-
}}
68-
</IntlConsumer>
69-
);
70-
};
50+
} = props => (
51+
<IntlConsumer>
52+
{intl => {
53+
if (enforceContext) {
54+
invariantIntlContext({intl});
55+
}
7156

57+
return (
58+
<WrappedComponent
59+
{...props}
60+
{...{
61+
[intlPropName]: intl,
62+
}}
63+
ref={forwardRef ? props.forwardedRef : null}
64+
/>
65+
);
66+
}}
67+
</IntlConsumer>
68+
);
7269
WithIntl.displayName = `injectIntl(${getDisplayName(WrappedComponent)})`;
7370
WithIntl.WrappedComponent = WrappedComponent;
7471

src/format.ts

+11-14
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ import {
2424
} from './types';
2525

2626
import {createError, escape, filterProps} from './utils';
27-
import {
27+
import IntlRelativeTimeFormat, {
2828
IntlRelativeTimeFormatOptions,
29-
FormattableUnit,
3029
} from '@formatjs/intl-relativetimeformat';
3130
import {LiteralElement, TYPE} from 'intl-messageformat-parser';
3231
import {FormatXMLElementFn, PrimitiveType} from 'intl-messageformat/core';
@@ -105,11 +104,10 @@ export function formatDate(
105104
timeZone,
106105
}: Pick<IntlConfig, 'locale' | 'formats' | 'onError' | 'timeZone'>,
107106
state: Formatters,
108-
value: number | Date,
107+
value: Parameters<Intl.DateTimeFormat['format']>[0],
109108
options: FormatDateOptions = {}
110109
) {
111110
const {format} = options;
112-
let date = new Date(value);
113111
let defaults = {
114112
...(timeZone && {timeZone}),
115113
...(format && getNamedFormat(formats!, 'date', format, onError)),
@@ -121,12 +119,12 @@ export function formatDate(
121119
);
122120

123121
try {
124-
return state.getDateTimeFormat(locale, filteredOptions).format(date);
122+
return state.getDateTimeFormat(locale, filteredOptions).format(value);
125123
} catch (e) {
126124
onError(createError('Error formatting date.', e));
127125
}
128126

129-
return String(date);
127+
return String(value);
130128
}
131129

132130
export function formatTime(
@@ -137,11 +135,10 @@ export function formatTime(
137135
timeZone,
138136
}: Pick<IntlConfig, 'locale' | 'formats' | 'onError' | 'timeZone'>,
139137
state: Formatters,
140-
value: number,
138+
value: Parameters<Intl.DateTimeFormat['format']>[0],
141139
options: FormatDateOptions = {}
142140
) {
143141
const {format} = options;
144-
let date = new Date(value);
145142
let defaults = {
146143
...(timeZone && {timeZone}),
147144
...(format && getNamedFormat(formats!, 'time', format, onError)),
@@ -162,12 +159,12 @@ export function formatTime(
162159
}
163160

164161
try {
165-
return state.getDateTimeFormat(locale, filteredOptions).format(date);
162+
return state.getDateTimeFormat(locale, filteredOptions).format(value);
166163
} catch (e) {
167164
onError(createError('Error formatting time.', e));
168165
}
169166

170-
return String(date);
167+
return String(value);
171168
}
172169

173170
export function formatRelativeTime(
@@ -177,8 +174,8 @@ export function formatRelativeTime(
177174
onError,
178175
}: Pick<IntlConfig, 'locale' | 'formats' | 'onError'>,
179176
state: Formatters,
180-
value: number,
181-
unit: FormattableUnit = 'second',
177+
value: Parameters<IntlRelativeTimeFormat['format']>[0],
178+
unit: Parameters<IntlRelativeTimeFormat['format']>[1] = 'second',
182179
options: FormatRelativeTimeOptions = {}
183180
) {
184181
const {format} = options;
@@ -208,7 +205,7 @@ export function formatNumber(
208205
onError,
209206
}: Pick<IntlConfig, 'locale' | 'formats' | 'onError'>,
210207
state: Formatters,
211-
value: number,
208+
value: Parameters<Intl.NumberFormat['format']>[0],
212209
options: FormatNumberOptions = {}
213210
) {
214211
const {format} = options;
@@ -228,7 +225,7 @@ export function formatNumber(
228225
export function formatPlural(
229226
{locale, onError}: Pick<IntlConfig, 'locale' | 'onError'>,
230227
state: Formatters,
231-
value: number,
228+
value: Parameters<Intl.PluralRules['select']>[0],
232229
options: FormatPluralOptions = {}
233230
) {
234231
let filteredOptions = filterProps(options, PLURAL_FORMAT_OPTIONS);

src/types.ts

+16-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
} from 'intl-messageformat/core';
1313
import IntlRelativeTimeFormat, {
1414
IntlRelativeTimeFormatOptions,
15-
FormattableUnit,
1615
} from '@formatjs/intl-relativetimeformat';
1716
import {MessageFormatElement} from 'intl-messageformat-parser';
1817

@@ -57,17 +56,26 @@ export type FormatPluralOptions = Exclude<
5756
CustomFormatConfig;
5857

5958
export interface IntlFormatters {
60-
formatDate(value: string | number | Date, opts: FormatDateOptions): string;
61-
formatTime(value: string | number | Date, opts: FormatDateOptions): string;
59+
formatDate(
60+
value: Parameters<Intl.DateTimeFormat['format']>[0],
61+
opts?: FormatDateOptions
62+
): string;
63+
formatTime(
64+
value: Parameters<Intl.DateTimeFormat['format']>[0],
65+
opts?: FormatDateOptions
66+
): string;
6267
formatRelativeTime(
63-
value: number,
64-
unit?: FormattableUnit,
68+
value: Parameters<IntlRelativeTimeFormat['format']>[0],
69+
unit?: Parameters<IntlRelativeTimeFormat['format']>[0],
6570
opts?: FormatRelativeTimeOptions
6671
): string;
67-
formatNumber(value: number, opts: FormatNumberOptions): string;
72+
formatNumber(
73+
value: Parameters<Intl.NumberFormat['format']>[0],
74+
opts?: FormatNumberOptions
75+
): string;
6876
formatPlural(
69-
value: number,
70-
opts: FormatPluralOptions
77+
value: Parameters<Intl.PluralRules['select']>[0],
78+
opts?: FormatPluralOptions
7179
): ReturnType<Intl.PluralRules['select']>;
7280
formatMessage(
7381
descriptor: MessageDescriptor,

test/unit/components/date.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('<FormattedDate>', () => {
3939
expect(isFinite(value)).toBe(true);
4040
expect(consoleError).toHaveBeenCalledTimes(0);
4141

42-
mountWithProvider({value: undefined}, intl);
42+
mountWithProvider({value: NaN}, intl);
4343
expect(consoleError).toHaveBeenCalledTimes(1);
4444
expect(consoleError.mock.calls[0][0]).toContain(
4545
'[React Intl] Error formatting date.\nRangeError'

test/unit/components/html-message.tsx

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import * as React from 'react';
22
import {mountFormattedComponentWithProvider} from '../testUtils';
3-
import FormattedHTMLMessage, {
4-
BaseFormattedHTMLMessage,
5-
} from '../../../src/components/html-message';
6-
import {BaseFormattedMessage} from '../../../src/components/message';
3+
import FormattedHTMLMessage from '../../../src/components/html-message';
74
import {createIntl} from '../../../src/components/provider';
85

96
const mountWithProvider = mountFormattedComponentWithProvider(
@@ -31,10 +28,6 @@ describe('<FormattedHTMLMessage>', () => {
3128
expect(FormattedHTMLMessage.displayName).toBeA('string');
3229
});
3330

34-
it('extends FormattedMessage', () => {
35-
expect(BaseFormattedHTMLMessage.prototype).toBeA(BaseFormattedMessage);
36-
});
37-
3831
it('renders a formatted HTML message in a <span>', () => {
3932
const descriptor = {
4033
id: 'hello',

test/unit/components/time.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('<FormattedTime>', () => {
3737

3838
injectIntlContext.setProps({
3939
...injectIntlContext.props(),
40-
value: undefined,
40+
value: NaN,
4141
});
4242
expect(consoleError).toHaveBeenCalledTimes(1);
4343
expect(consoleError.mock.calls[0][0]).toContain(

test/unit/format.ts

+14-22
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,14 @@ describe('format API', () => {
116116
formatDate = f.formatDate.bind(null, config, state);
117117
});
118118

119-
it('fallsback and warns when no value is provided', () => {
120-
expect(formatDate()).toBe('Invalid Date');
121-
expect(consoleError).toHaveBeenCalledTimes(1);
122-
expect(consoleError.mock.calls[0][0]).toContain(
123-
'[React Intl] Error formatting date.\nRangeError'
124-
);
119+
it('no value should render today', () => {
120+
expect(formatDate()).toBe(df.format());
125121
});
126122

127123
it('fallsback and warns when a non-finite value is provided', () => {
128-
expect(formatDate(NaN)).toBe('Invalid Date');
129-
expect(formatDate('')).toBe('Invalid Date');
130-
expect(consoleError).toHaveBeenCalledTimes(2);
124+
expect(formatDate(NaN)).toBe('NaN');
125+
expect(formatDate('')).toBe(df.format(''));
126+
expect(consoleError).toHaveBeenCalledTimes(1);
131127
});
132128

133129
it('formats falsy finite values', () => {
@@ -141,7 +137,7 @@ describe('format API', () => {
141137
});
142138

143139
it('formats date string values', () => {
144-
expect(formatDate(new Date(0).toString())).toBe(df.format(new Date(0)));
140+
expect(formatDate(new Date(0).toString())).toBe(new Date(0).toString());
145141
});
146142

147143
it('formats date ms timestamp values', () => {
@@ -175,7 +171,7 @@ describe('format API', () => {
175171
});
176172

177173
it('fallsback and warns on invalid Intl.DateTimeFormat options', () => {
178-
expect(formatDate(0, {year: 'invalid'})).toBe(String(new Date(0)));
174+
expect(formatDate(0, {year: 'invalid'})).toBe('0');
179175
expect(consoleError).toHaveBeenCalledTimes(1);
180176
expect(consoleError.mock.calls[0][0]).toContain(
181177
'[React Intl] Error formatting date.\nRangeError'
@@ -246,18 +242,14 @@ describe('format API', () => {
246242
formatTime = f.formatTime.bind(null, config, state);
247243
});
248244

249-
it('fallsback and warns when no value is provided', () => {
250-
expect(formatTime()).toBe('Invalid Date');
251-
expect(consoleError).toHaveBeenCalledTimes(1);
252-
expect(consoleError.mock.calls[0][0]).toContain(
253-
'[React Intl] Error formatting time.\nRangeError'
254-
);
245+
it('render now if no value is provided', () => {
246+
expect(formatTime()).toBe(df.format());
255247
});
256248

257249
it('fallsback and warns when a non-finite value is provided', () => {
258-
expect(formatTime(NaN)).toBe('Invalid Date');
259-
expect(formatTime('')).toBe('Invalid Date');
260-
expect(consoleError).toHaveBeenCalledTimes(2);
250+
expect(formatTime(NaN)).toBe('NaN');
251+
expect(formatTime('')).toBe(df.format(''));
252+
expect(consoleError).toHaveBeenCalledTimes(1);
261253
});
262254

263255
it('formats falsy finite values', () => {
@@ -271,7 +263,7 @@ describe('format API', () => {
271263
});
272264

273265
it('formats date string values', () => {
274-
expect(formatTime(new Date(0).toString())).toBe(df.format(new Date(0)));
266+
expect(formatTime(new Date(0).toString())).toBe(new Date(0).toString());
275267
});
276268

277269
it('formats date ms timestamp values', () => {
@@ -309,7 +301,7 @@ describe('format API', () => {
309301
});
310302

311303
it('fallsback and warns on invalid Intl.DateTimeFormat options', () => {
312-
expect(formatTime(0, {hour: 'invalid'})).toBe(String(new Date(0)));
304+
expect(formatTime(0, {hour: 'invalid'})).toBe('0');
313305
expect(consoleError).toHaveBeenCalledTimes(1);
314306
expect(consoleError.mock.calls[0][0]).toContain(
315307
'[React Intl] Error formatting time.\nRangeError'

0 commit comments

Comments
 (0)