Extend lodash types (@types/lodash) with an interface of "first" method for my project

Viewed 977

ISSUE: I found @types/lodash method first doesn't cover the case type of the input is union of two (multiple) typed arrays: // In my file I have import * as _ from 'lodash';

interface First {
  name: string;
}

interface Second {
  age: number;
}

function performSomeLogic(): First[] | Second[] {
  if (Math.random() > 0.5) return [{name: 'Alice'}, {name: 'Bob'}];
  return [{age: 42}, {age: 33}];
}

// we got some array First or Second of type. ok
const returnedData = performSomeLogic(); // we got some array First or Second of type. ok

// we expect value is First or Second of type. NOT ok.

// *******************
// TS ERROR
// TS2345: Argument of type 'First[] | Second[]' is not assignable to 
// parameter of type 'ArrayLike<First>'.
// *******************
const firstValueOfData = _.first(returnedData); 

// further steps could be ..
const proceedWithValueOfData = (value: First | Second) => Object.keys(value);
proceedWithValueOfData(firstValueOfData);

IDEA: I came up with the proper interface for _.first(). I try to put it into the typings.d.ts add refer it for bundler:

// typings.d.ts
type DeriveArrTypes<T> = T extends (infer R)[] ? R : T;

// So DeriveArrTypes<First[] | Second[]> returns First|Second union

declare module 'lodash' {
  // LoDashStatic IS THE INTERFACE LODASH HAS HAD. FIRST IS DECLARED IN IT. I WANT TO ADD ITS EXTENDED DECLARATION
  interface LoDashStatic {
    first<T extends []>(value: T): DeriveArrTypes<T> | undefined;
  }
}

SUCCESS - NO: But that doesn't work. Typescript stops displaying any errors (including others different). I use WebStorm as IDE it continue highlighting.

ENV: It is a frontend project that is served by Typescript for transpiling and Webpack for bundling (due to its long continuous liveness :)). From webpack.config.js:

       // the rule for ts
       {
            test: /\.ts$/,
            use: [{
                loader: 'ts-loader',
                options: {
                    // disable type checker - we will use it in fork plugin
                    transpileOnly: true
                }
            }],
        },

       // plugins section
       plugins: [
         // bla-bla plugins
         ...

        new ForkTsCheckerWebpackPlugin({
          tsconfig: __dirname + '/tsconfig.json'
        })
      ]

From tsconfig.json:

"compilerOptions": {
      // bla-bla options
      ... 

      "typeRoots": [
        "node_modules/@types"
      ],
 }

 // I ADDED THIS
 "include": [
    "app/typings/**/*"
  ],

As I created app/typings directory and put typings.d.ts into it.

1 Answers

If you want to add interface to a npm module you can use declare module keyword

import lodash  from "lodash";
declare module "lodash " {
    interface First {
       name: string;
    }

    interface Second {
      age: number;
    }
}
Related