telerik / kendo-angular

Issue tracker - Kendo UI for Angular
http://www.telerik.com/kendo-angular-ui/
Other
466 stars 215 forks source link

ZonedDate implements Date which forbids user to extend DateObject #2706

Open MaklaCof opened 4 years ago

MaklaCof commented 4 years ago

Describe the bug I am getting this error, after upgrading Angular (7 to 8) & Kendo(approx. 1.5 year old):

ERROR in node_modules/@progress/kendo-date-math/dist/npm/tz/zoned-date.d.ts(38,22): error TS2420: Class 'ZonedDate' incorrectly implements interface 'Date'. Type 'ZonedDate' is missing the following properties from type 'Date': addMinutes, addMonths, fixTimezone, toSQLString

I extend Date object with some methods that I regularly use. But now, kendo compiles with error.

To Reproduce I included in main file with this content:

export function addMinutes(date: Date, minutes: number): Date
{
    return new Date(date.getTime() + minutes * 60000);
}

export function addMonths(date: Date, months: number): Date
{
    const result = new Date(date.getTime());
    result.setMonth(result.getMonth() + months);
    return result;
}

export function fixTimezone(date: Date): Date
{
    return new Date(date.getTime() - (date.getTimezoneOffset() * 1 * 60 * 1000));
}

export function toSQLString(date: Date): string
{
    return `${date.getUTCFullYear()}-${date.getUTCMonth() + 1}-${date.getUTCDate()} ${date.getUTCHours()}:${date.getUTCMinutes()}:${date.getUTCSeconds()}`;
}

declare global
{
    interface Date
    {
        addMinutes(minutes: number): Date;
        addMonths(months: number): Date;
        fixTimezone(): Date;
        toSQLString(): string;
    }
}

Date.prototype.addMinutes = function (minutes: number): Date
{
    return addMinutes(this, minutes);
}

Date.prototype.addMonths = function (months: number): Date
{
    return addMonths(this, months);
}

Date.prototype.fixTimezone = function (): Date
{
    return fixTimezone(this);
}

Date.prototype.toSQLString = function (): string
{
    return toSQLString(this);
}

Expected behavior No compiler error. Extending plain JavaScript object is something user could do, and kendo should compile successfully.

Screenshots If applicable, add screenshots to help explain your problem. image

Browser

tsvetomir commented 4 years ago

That's a tricky problem! The only workaround I can think of is to use optional properties instead of methods on the global Date:

declare global
{
  interface Date
  {
    addMinutes?: (minutes: number) => Date;
    addMonths?: (months: number) => Date;
    fixTimezone?: () => Date;
    toSQLString?: () => string;
  }
}

In hindsight, extending Date in ZonedDate was probably not such a great idea 👀

ChristianGalla commented 3 years ago

Because SharePoint is also extending the Date object @types/sharepoint cannot be used at the same time:

EXEC : error : node_modules/@progress/kendo-date-math/dist/npm/tz/zoned-date.d.ts:38:22 - error TS2420: Class 'ZonedDate' incorrectly implements interface 'Date'.
    Property 'localeFormat' is missing in type 'ZonedDate' but required in type 'Date'.

  38 export declare class ZonedDate implements Date {
                          ~~~~~~~~~

    node_modules/@types/microsoft-ajax/index.d.ts:144:5
      144     localeFormat(format: string): string;
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      'localeFormat' is declared here.

package.json:

{
  "name": "my-sharepoint-addin",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~11.2.13",
    "@angular/common": "~11.2.13",
    "@angular/compiler": "~11.2.13",
    "@angular/core": "~11.2.13",
    "@angular/forms": "~11.2.13",
    "@angular/localize": "~11.2.13",
    "@angular/platform-browser": "~11.2.13",
    "@angular/platform-browser-dynamic": "~11.2.13",
    "@angular/router": "~11.2.13",
    "@progress/kendo-angular-buttons": "^6.2.0",
    "@progress/kendo-angular-common": "^2.0.0",
    "@progress/kendo-angular-dateinputs": "^5.2.1",
    "@progress/kendo-angular-dropdowns": "^5.3.0",
    "@progress/kendo-angular-excel-export": "^4.0.1",
    "@progress/kendo-angular-grid": "^5.2.1",
    "@progress/kendo-angular-inputs": "^7.3.0",
    "@progress/kendo-angular-intl": "^3.0.0",
    "@progress/kendo-angular-l10n": "^3.0.0",
    "@progress/kendo-angular-label": "^3.0.3",
    "@progress/kendo-angular-pdf-export": "^3.0.1",
    "@progress/kendo-angular-popup": "^4.0.0",
    "@progress/kendo-angular-treeview": "^5.3.1",
    "@progress/kendo-data-query": "^1.5.5",
    "@progress/kendo-drawing": "^1.5.12",
    "@progress/kendo-licensing": "^1.2.0",
    "@progress/kendo-theme-default": "latest",
    "rxjs": "~6.6.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.11.3"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1102.12",
    "@angular/cli": "~11.2.12",
    "@angular/compiler-cli": "~11.2.13",
    "@types/jasmine": "~3.6.0",
    "@types/node": "^12.11.1",
    "@types/sharepoint": "^2016.1.10",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~3.6.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.1.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "~4.1.5"
  }
}
tsvetomir commented 3 years ago

@ChristianGalla can you get around this error by declaring it as optional field in the global scope?

declare global
{
  interface Date
  {
    localeFormat?: (format: string) => string;
  }
}
ChristianGalla commented 3 years ago

@tsvetomir adding

interface Date
{
  localeFormat?: (format: string) => string;
}

to my local typings.d.ts throws

error TS2300: Duplicate identifier 'localeFormat'.

Changing this method to be optional in node_modules\@types\microsoft-ajax\index.d.ts is working. I am considering to create a PR to change this in @types\microsoft-ajax.