Search code examples
typescriptwindowglobaltyping

How do I access a global object in TypeScript if it is concealed?


Let's assume we have the following TypeScript code:

namespace Utils.Date {
    export fromInternal = (dateString: string): Date => {
        const year = parseInt(dateString.substr(0, 4), 10);
        const month = parseInt(dateString.substr(4, 2), 10) - 1;
        const day = parseInt(dateString.substr(6, 2), 10);

        return new Date(year, month, day); // error TS2351
    }
}

This causes error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature, because the namespace Utils.Date now conceals the built-in Date constructor.

I know I can can use window.Date to access the Date constructor in the browser, but when I try to do that in TypeScript I get error TS2339: Property 'Date' does not exist on type 'Window'. Instead I would have to use something like window['Date'], but then I'd lose the type safety.

Is there a way to access the Date constructor without changing the namespace and still being typesafe? Or is it simply bad practice to conceal global objects? Even then I'm curious to know if there would be a way.


Solution

  • My preferred solution is to avoid the name clash, especially where your code is so closely related to the clashed name. The name clash will eventually affect more and moer things that you add to the Utils namespace.

    namespace Utils.DateParsers {
    

    But you could shim the Date object into an intermediate variable if you are determined to keep the name clash.

    const outerDate = Date;
    
    namespace Utils.Date {
        const fromInternal = (dateString: string): Date => {
            const year = parseInt(dateString.substr(0, 4), 10);
            const month = parseInt(dateString.substr(4, 2), 10) - 1;
            const day = parseInt(dateString.substr(6, 2), 10);
    
            return new outerDate(year, month, day); // error TS2351
        }
    }