1

Webpack provides a TypeScript interface for implementing a loader:

import { loader } from "webpack";

namespace loader {
  interface Loader extends Function {
      (this: LoaderContext, source: string | Buffer, sourceMap?: RawSourceMap): string | Buffer | void | undefined;
      pitch?(remainingRequest: string, precedingRequest: string, data: any): any;
      raw?: boolean;
  }
}

So when I implement that I do

const sfcLoader: loader.Loader = function(source: string) {
  /* ... */
};

Now I am trying to create an interface that is that interface but returns a Promise:

const sfcLoader /* : loader.Loader */ = async function(source: string) {
  /* await ... */
};

Note that async

Of course I don't want to copy and paste that interface. Is there a way I can extend (or something) and modify the interface from webpack?

Lukas
  • 9,752
  • 15
  • 76
  • 120

1 Answers1

1

You need to create a mapped type based on your loader interface. The idea is that you need to use the keyword infer to get access to the existing return type of the function. In your case, you'd need to wrap the return type into a Promise, I guess. Try this code sample in TypeScript Playground (we wrote it for the book "TypeScript Quickly"):

type ReturnPromise<T> =
    T extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : T;   

type Promisify<T> = {
    [P in keyof T]: ReturnPromise<T[P]>;
};

interface SyncService {
    baseUrl: string; 
    getA(): string;
}

class AsyncService implements Promisify<SyncService> {
    baseUrl: string; 

    getA(): Promise<string> {
        return Promise.resolve('');
    }
}

let service = new AsyncService();


let result = service.getA(); // hover over result: it's of type Promise<string>

Here, we declare a new type Promisify<T>. To test it, we take the interface SyncService, find its properties that are methods (getA() in this case), and wrap its return type into Promise.

Yakov Fain
  • 11,972
  • 5
  • 33
  • 38