I'm working with MomentTimezone for time manipulation in the browser.
I am using TypeScript and Lodash too.
I have some accountTimezone
set on the window
containing the authenticated user's preferred timezone. I am trying to create a helper method localMoment()
that will accept any of the many signatures of moment.tz()
, appending this window.accountTimezone
as the final timezone: string
argument.
It seems partialRight
may be what I'm looking for.
const localMoment = partialRight(moment.tz, window.accountTimezone);
The problem I'm having has to do with this note from the lodash docs:
Note: This method doesn't set the "length" property of partially applied functions.
Specifically, for a call like localMoment('2019-08-01 12:00:00')
, TypeScript complains that localMoment()
was provided 1 argument, but expects zero.
How can I keep TypeScript happily understanding a call to localMoment()
should look like a call to moment.tz()
via the MomentTimzone
interface, while avoiding this arity confusion from the use of partialRight()
?
I considered something like this as an alternative, but don't know how to type ...args
to keep TypeScript happy.
const localMoment = (...args): Moment => moment.tz(...args, window.accountTimezone);
There is no clean way to do this. You either have to opt out of typing or redeclare an interface of your own.
Typescript himself can't do this and just opt for the "good-enough" solution of declaring a bunch of different signatures: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/common/function.d.ts#L1147
Even if you somehow manage to manipulate the typescript interface, I doubt you could handle the other methods (zone
, add
, link
, ...) which don't have a timezone parameter:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/moment-timezone/moment-timezone.d.ts#L20
The best you can achieve is avoiding duplicating the whole interface using the Pick
utility type:
type CurriedMomentTimezone = Pick<moment.MomentTimezone, 'zone' | 'add' | 'link' | 'load' | 'names' | 'guess' | 'setDefault'> & {
(): moment.Moment;
(date: number): moment.Moment;
(date: number[]): moment.Moment;
(date: string): moment.Moment;
(date: string, format: moment.MomentFormatSpecification): moment.Moment;
(date: string, format: moment.MomentFormatSpecification, strict: boolean): moment.Moment;
(date: string, format: moment.MomentFormatSpecification, language: string): moment.Moment;
(date: string, format: moment.MomentFormatSpecification, language: string, strict: boolean): moment.Moment;
(date: Date): moment.Moment;
(date: moment.Moment): moment.Moment;
(date: any): moment.Moment;
}
localMoment = _.partialRight(moment.tz, this.accountTimezone) as CurriedMomentTimezone;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With