Search code examples
javascriptnode.jstypescriptgulppostcss

`gulp-postcss is not a function` type error when it provided by gulp-load-plugins


I make some kind of mistake when extended TypeScirpt interface IGulpPlugins from type definitions for gulp-load-plugins, or incorrectly defined types of gulp-postcss.

According comment in index.d.ts of @types/gulp-load-plugins:

/**
 * Extend this interface to use Gulp plugins in your gulpfile.js
 */
interface IGulpPlugins {
}

All of below plugins except gulp-postcss works.

import * as gulpDebug from 'gulp-debug';
import * as gulpPlumber from 'gulp-plumber';
import * as gulpIntercept from 'gulp-intercept';
import * as gulpIf from 'gulp-if';
import * as gulpPug from 'gulp-pug';
import * aas gulpHtmlPrettify from 'gulp-html-prettify';
import * as gulpSass from 'gulp-sass';
import * as gulpStylus from 'gulp-stylus';
import * as gulpSourcemaps from 'gulp-sourcemaps';
import * as gulpPostCss from 'gulp-postcss';

export interface IGulpPlugins {
  plumber: typeof gulpPlumber;
  debug: typeof gulpDebug;
  intercept: typeof gulpIntercept;
  if: typeof gulpIf;
  pug: typeof gulpPug;
  htmlPrettify: typeof gulpHtmlPrettify;
  sass: typeof gulpSass;
  stylus: typeof gulpStylus;
  postCss: typeof gulpPostCss;
  sourcemaps: typeof gulpSourcemaps;
}

The are no TypseScript compiling errors in below code, however if to execute compiled TypeScript, TypeError: gulpPlugins.postCss is not a function error will occurs.

import * as gulp from 'gulp';
import * as GulpPlugins from 'gulp-load-plugins';

// I did not create types for this libary yet, so temporary make TypeScript to ignore it
// @ts-ignore
import * as postcssNormalizeWhitespace from 'postcss-normalize-whitespace';

gulpPlugins: IGulpPlugins = GulpPlugins();

return gulp.src(SOURCE_FILES_GLOB_SELECTION)
    .pipe(gulpPlugins.postCss([postcssNormalizeWhitespace]))
    .pipe(gulp.dest('build'));

If to write

import * as gulp from 'gulp';
import * as GulpPlugins from 'gulp-load-plugins';

/* When I wrote this question, types in DefinitelyTyped for this library was not exists yet,
 * but I created it. However did not create the pull request yet.
 */
import * as gulpPostCss from 'gulp-postcss';

// I did not create types for this libary yet, so temporary make typescript ingore it
// @ts-ignore
import * as postcssNormalizeWhitespace from 'postcss-normalize-whitespace';


return gulp.src(SOURCE_FILES_GLOB_SELECTION)
    .pipe(gulpPostCss([postcssNormalizeWhitespace]))
    .pipe(gulp.dest('build'));

instead, JavaScript will work without errors.

I can not understand, where I did mistake. Let me repeat that all plugins in extended IGulpPlugins except gulp-postcss works.

The types for gulp-postcss that I wrote are:

/// <reference types="node"/>
import Vinyl = require('vinyl');

declare function GulpPostCss(plugins?: Array<string>, options?: GulpPostCss.Options): NodeJS.ReadWriteStream;
declare function GulpPostCss(callback?: (file: Vinyl) => { plugins?: Array<string>, options?: GulpPostCss.Options }): NodeJS.ReadWriteStream;

declare namespace GulpPostCss {
    interface Options {
        parser?: string;
    }
}

export = GulpPostCss;

Solution

  • There are 2 things you didn't get right.

    1. You made a typo, or maybe don't understand how gulp-load-plugins works.

    If your plugin name is gulp-post-css, then it becomes gulpPlugins.postCss. However, that plugin name is gulp-postcss, so it will be:

    gulpPlugins.postcss(...) // NOT gulpPlugins.postCss !!!
    
    1. You don't understand typescript.

    This has nothing to do with typescript.

    Here's a rule of thumb: typescript has zero impact on javascript runtime behaviour. Whenever you find a runtime error, it must come from the javascript side of typescript.

    Though 1. has already solved your problem, let's pretend you MUST use gulpPlugins.postCss. In order for this to work, try add these lines:

    import * as gulpPostCss from 'gulp-postcss';
    gulpPlugins.postCss = gulpPostCss;
    

    Now it'll work.