简体   繁体   中英

How to deal with optional tuple element when using rest parameters to forward arguments to curried function (with strictNullChecking)

The goal: Get rid of the typescript error TS2345 where argument is not assignable to parameter

The Problem: Im trying to curry an arrow function by forwarding all the arguments using a rest parameter and tuple as type. However, because I use a optional element and strictNullChecking it throws an error because it passes on an undefined type as possibility whilst it should (and will not use) the parameter at all if argument is not given.

The Code (Its about the lower functions parse, format, convert):

/* eslint-disable @typescript-eslint/ban-ts-ignore  */
import { parse, format } from 'date-fns'
import curry from 'lodash/curry'

type Formats = { [key: string]: string }
type Parse = [(keyof Formats), string?]
type Format = [keyof Formats, (Date | number)?]
type Convert = [keyof Formats, keyof Formats, string?]

// if you need prototype inheritance then convert functions to methods and bind
export class DateFormatter<T extends Formats> {
  formats: T

  constructor (formats: T) {
    this.formats = formats
  }

  parseToDate = (formatType: keyof T, date: string): Date => {
    return parse(date, this.formats[formatType], new Date())
  }

  formatToString = (formatType: keyof T, date: Date | number) => {
    return format(date, this.formats[formatType])
  }

  convertFormat = (from: keyof T, to: keyof T, formattedDate: string): string => {
    return format(parse(formattedDate, this.formats[from], new Date()), this.formats[to])
  }

  // @ts-ignore
  parse = (...args: Parse) => curry(this.parseToDate).apply(this, args)
  // @ts-ignore
  format = (...args: Format) => curry(this.formatToString).apply(this, args)
  // @ts-ignore
  convert = (...args: Convert) => curry(this.convertFormat).apply(this, args)
}

Sandbox https://codesandbox.io/s/summer-fog-sw7qb?fontsize=14&hidenavigation=1&theme=dark

Any tips and help much appreciated!

Answer by jcalz:

import { parse, format } from "date-fns";
import _ from "lodash";

type Formats = { [key: string]: string };
type Parse = [(keyof Formats), string?];
type Format = [keyof Formats, (Date | number)?];
type Convert = [keyof Formats, keyof Formats, string?];

// if you need prototype inheritance then convert functions to methods and bind
export class DateFormatter<T extends Formats> {
  formats: T;

  constructor(formats: T) {
    this.formats = formats;
  }

  parseToDate = (formatType: keyof T, date: string): Date => {
    return parse(date, this.formats[formatType], new Date());
  };

  formatToString = (formatType: keyof T, date: Date | number) => {
    return format(date, this.formats[formatType]);
  };

  convertFormat = (
    from: keyof T,
    to: keyof T,
    formattedDate: string
  ): string => {
    return format(
      parse(formattedDate, this.formats[from], new Date()),
      this.formats[to]
    );
  };

  parse: {
    (formatType: keyof T, date: string): Date;
    (formatType: keyof T): (date: string) => Date
  } = (...args: any) => _.curry(this.parseToDate).apply(this, args) as any;

  format: {
    (formatType: keyof T, date: Date | number): string;
    (formatType: keyof T):(date: Date | number) => string;
  } = (...args: any) => _.curry(this.formatToString).apply(this, args) as any;

  convert: {
    (from: keyof T, to: keyof T, formattedDate: string): string;
    (from: keyof T, to: keyof T): (formattedDate: string) => string;
  } = (...args: any) => _.curry(this.convertFormat).apply(this, args) as any;
}

Thanks!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM