Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,25 @@ describe('stringify & parse', () => {
},
},

'works for invalid dates': {
input: {
date: new Date('invalid'),
},
output: {
date: 'Invalid Date',
},
outputAnnotations: {
values: {
date: ['Date'],
},
},
dontExpectEquality: true,
customExpectations: value => {
expect(value.date).toBeInstanceOf(Date);
expect(Number.isNaN(value.date.getTime())).toBe(true);
},
},

'works for Errors': {
input: {
e: new Error('epic fail'),
Expand Down Expand Up @@ -1431,3 +1450,23 @@ test('#310 fixes backwards compat', () => {
},
});
});

test('#355 invalid dates are backwards compatible', () => {
// payloads from previous versions (ISO strings) still parse unchanged
const date = new Date(2020, 1, 1);
expect(
SuperJSON.deserialize({
json: { date: date.toISOString() },
meta: { values: { date: ['Date'] } },
})
).toEqual({ date });

// the "Invalid Date" sentinel goes through the same `new Date(string)`
// path older versions use, so they revive it to an invalid Date too
const result = SuperJSON.deserialize<{ date: Date }>({
json: { date: 'Invalid Date' },
meta: { values: { date: ['Date'] } },
});
expect(result.date).toBeInstanceOf(Date);
expect(Number.isNaN(result.date.getTime())).toBe(true);
});
9 changes: 6 additions & 3 deletions src/transformer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
isBigint,
isDate,
isInfinite,
isMap,
isNaNValue,
Expand Down Expand Up @@ -73,9 +72,13 @@ const simpleRules = [
}
),
simpleTransformation(
isDate,
(v): v is Date => v instanceof Date,
'Date',
v => v.toISOString(),
// An invalid Date (`new Date(NaN)`) has no ISO representation and would
// otherwise be dropped to `null`, losing its type. Serialize it as
// "Invalid Date", which `new Date('Invalid Date')` revives back into an
// invalid Date - also on older versions that just call `new Date(v)`.
v => (isNaN(v.valueOf()) ? 'Invalid Date' : v.toISOString()),
v => new Date(v)
),

Expand Down