Why do my .d.ts interface extensions not work?

Viewed 151

I'm having a real battle trying to get .d.ts files working properly within a monorepo. What I'm trying to do is extend a material-ui interface and then export that updated type to be consumed in multiple other places.

types/src/material-ui.d.ts

declare module "@material-ui/core" {
    interface CommonColors {
        amberGreen: string;
        green2: string;
        red2: string;
        yellow2: string;
    }
}

types/src/index.ts

import "./material-ui.d.ts";

export {};

I've tried all sorts of ways of importing this though and trawled numerious StackOverflow questions, but I'm unable to make it work. red2 in my other package is always undefined. Currently I'm using:

mui-test/src/index.ts

import { useTheme } from "@material-ui/core";
import "@iw/types";

export const useMUITest = (): void => {
    const theme = useTheme();

    console.log(theme.palette);
    console.log(theme.palette.common);
    console.log(theme.palette.common.red2);
};

I've a full reproduction of the issue here https://github.com/IPWright83/pnpm-monorepo/tree/d-ts

@iw/mui-test:build: src/index.ts(9,38): error TS2339: Property 'red2' does not exist on type 'CommonColors'.
@iw/mui-test:build:  ELIFECYCLE  Command failed with exit code 2.
@iw/mui-test:build: ERROR: command finished with error: command (packages/mui-test) pnpm run build exited (1)
2 Answers

Your file material-ui.d.ts should first be named index.d.ts first. You should use the export keyword also, such as:

declare module "@material-ui/core" {
    export interface CommonColors {
        amberGreen: string;
        green2: string;
        red2: string;
        yellow2: string;
    }
}

You should also export by default your interface in its definition file, such as:

export interface CommonColors {
    amberGreen: string;
    green2: string;
    red2: string;
    yellow2: string;
}
export default CommonColors;

First, add a new folder for @material-ui/core in your types/src directory. Then, move material-ui.d.ts to the directory @material-ui/core/styles and rename it createPalette.d.ts. The contents should look like this:

declare module "@material-ui/core/styles/createPalette" {
    interface CommonColors {
        amberGreen: string;
        green2: string;
        red2: string;
        yellow2: string;
    }
}

Then, in tsconfig.json add this to your typeRoots:

"compilerOptions": {
    "typeRoots": [
        "node_modules/@types",
        "types/src"
    ]
}

You don't need to import this module; TypeScript should use it based on what we told it from the config.

Thus, your file tree should look similar to the following:

example
│   tsconfig.json
│
├───mui-test
│   └───src
│           index.ts
│
└───types
    └───src
        └───@material-ui
            └───core
                └───styles
                        createPalette.d.ts
Related