1

Here is my typings.d.ts file from Angular 6 project:

import { Injectable, InjectableDecorator, HostBinding, HostBindingDecorator, HostListener, HostListenerDecorator } from '@angular/core';

// Those decorators are declared with `any` type by default. Because of that
// `no-unsafe-any` TSLint rule reports errors on for example `@Injectable`
// decorator. Below declarations fix that.
declare module '@angular/core' {
    export interface InjectableDecorator {
        (providedIn?: any | 'root' | null): ClassDecorator;
    }
    export const Injectable: InjectableDecorator;

    export interface HostBindingDecorator {
        (hostPropertyName?: string): PropertyDecorator;
    }
    export const HostBinding: HostBindingDecorator;

    export interface HostListenerDecorator {
        (eventName: string, args?: string[]): MethodDecorator;
    }
    export const HostListener: HostListenerDecorator;
}

// Allows to import JSON files inside TypeScript files
declare module '*.json' {
    const value: any;
    export default value;
}

The last declaration for '*.json should allow me to import JSON files inside TypeScript files (more details here). It doesn't work - TypeScript compiler reports an error when I'm importing JSON file:

ERROR in src/app/core/internationalization/build-time-translate-loader.ts(8,26): error TS2307: Cannot find module '../../../assets/i18n/translations.json'

The weird thing is that as soon as I move declare module '*.json' { ... } part from typings.d.ts to any other .d.ts file, e.g. json.d.ts the compiler stops complaining and JSON is imported properly without errors. The same happens when I move out declare module '@angular/core' { ... } part to another file. It makes me assume the problem is in both declarations coexisting in a single file.

Contrary to that TypeScript documentation states you can declare multiple modules in a single .d.ts file:

We could define each module in its own .d.ts file with top-level export declarations, but it’s more convenient to write them as one larger .d.ts file. To do so, we use a construct similar to ambient namespaces, but we use the module keyword and the quoted name of the module which will be available to a later import. For example:

declare module "url" {
    export interface Url {
        protocol?: string;
        hostname?: string;
        pathname?: string;
    }

    export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url;
}

declare module "path" {
    export function normalize(p: string): string;
    export function join(...paths: any[]): string;
    export var sep: string;
}

Which is exactly what I'm doing. Why it doesn't work, when both declare module are in the same file?

1 Answer 1

7

typings.d.ts is treated as an external module because it contains a top-level import. Hence, every declare module "..." { ... } statement in the file is treated as a module augmentation, not an original declaration of a module. The augmentation of "*.json" is discarded because no original declaration of "*.json" is available, and unfortunately you don't get an error when this happens in a .d.ts file; I'm unsure if there's a good reason for that. Putting the declare module "*.json" in a file with no top-level imports is the correct solution. Unfortunately, none of this is properly documented.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.