26

I'm working on a simple nodejs electron (formerly known as atom shell) project. I'm writing it using angular 2, using the project the same project setup as they recommend in the documentation for typescript:

tsc:

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
  "node_modules",
  "typings/main",
  "typings/main.d.ts"
  ]
}

I need to run a command, I found out that I can do it with node "child_process". I couldn't find anyway for me to "import" or "require" it while having its type used from the node.d.ts file. I have found the "child_process" interface in the node.d.ts file which suits my need, this is how it looking in the node.d.ts file:

    declare module "child_process" {
    import * as events from "events";
    import * as stream from "stream";

    export interface ChildProcess extends events.EventEmitter {
        stdin:  stream.Writable;
        stdout: stream.Readable;
        stderr: stream.Readable;
        pid: number;
        kill(signal?: string): void;
        send(message: any, sendHandle?: any): void;
        disconnect(): void;
        unref(): void;
    }

    export function spawn(command: string, args?: string[], options?: {
        cwd?: string;
        stdio?: any;
        custom?: any;
        env?: any;
        detached?: boolean;
    }): ChildProcess;
    export function exec(command: string, options: {
        cwd?: string;
        stdio?: any;
        customFds?: any;
        env?: any;
        encoding?: string;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
    }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function exec(command: string, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function execFile(file: string,
        callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function execFile(file: string, args?: string[],
        callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function execFile(file: string, args?: string[], options?: {
        cwd?: string;
        stdio?: any;
        customFds?: any;
        env?: any;
        encoding?: string;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
    }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function fork(modulePath: string, args?: string[], options?: {
        cwd?: string;
        env?: any;
        execPath?: string;
        execArgv?: string[];
        silent?: boolean;
        uid?: number;
        gid?: number;
    }): ChildProcess;
    export function spawnSync(command: string, args?: string[], options?: {
        cwd?: string;
        input?: string | Buffer;
        stdio?: any;
        env?: any;
        uid?: number;
        gid?: number;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
        encoding?: string;
    }): {
        pid: number;
        output: string[];
        stdout: string | Buffer;
        stderr: string | Buffer;
        status: number;
        signal: string;
        error: Error;
    };
    export function execSync(command: string, options?: {
        cwd?: string;
        input?: string|Buffer;
        stdio?: any;
        env?: any;
        uid?: number;
        gid?: number;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
        encoding?: string;
    }): string | Buffer;
    export function execFileSync(command: string, args?: string[], options?: {
        cwd?: string;
        input?: string|Buffer;
        stdio?: any;
        env?: any;
        uid?: number;
        gid?: number;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
        encoding?: string;
    }): string | Buffer;
}

but I can only (as I know of) get this type only by using import:

import * as child_process from 'child_process'; 

Only problem is that when I do this, my app cant load and I get the following error in the console:

GET file:///C:/angular2Samples/NGW-electron-VS%20-%20TEMP/child_process net::ERR_FILE_NOT_FOUND

For now, im getting my way around by using:

var child_process = require('child_process');

but I couldn't find anyway to add the type information to this var:

var child_process : I_CANT_PUT_ANY_CHILD_PROCESS_TYPE_HERE = require('child_process');

Any ideas on how I can get the child_process (or any other declared node modules that arent public interface that I can state after ":" operator) with type information?

Thanks alot in advance for any help and explanations :)

UPDATE ------------------------------------------------------------------

As tenbits suggested I have added the reference as follows to the top of the file: ///

and used the import statment you said, but didnt chage my module loader. it still didnt work with the same error as expected. Im not feeling very comfortable about changing the module system, as my project uses angular 2 and their docs and some of their guides said that new projects that has no former prefernce to this matter (I am very new to the module loaders scene and im not fully understanding how it works yet). When I tried to change it I got some errors regarding angular 2 stuffs which I dont have enough time to get into at the moment. Shouldn't there be a way to this without changing the module loader? by glancing at the systemjs site it says at the start that it supports commonjs modules: Systemjs doc

I would really appriciate a solution that doesn't change the module system, or maybe a more depth explanition about what's going on and which approaches to these kind of module loading problems exists out there

1
  • yep, TS makes everything more difficult. Commented Jun 15, 2023 at 17:58

4 Answers 4

52

Ok, after some research #L138 I have found the solution

You can use import as before

import * as child from 'child_process';

var foo: child.ChildProcess = child.exec('foo.sh');
console.log(typeof foo.on);

But you should configure SystemJS to map the module to NodeJS.

System.config({
  map: {
    'child_process': '@node/child_process'
  }
});

That's it!

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

15 Comments

I'm not quite got it: Have you tried import child = require('child_process'); instead of var child = require('child_process');? Do you have the same result as with var?
Yes, exactly the same (notice that I didnt change the module to commonjs as you suggested, the reason for that is noted in my update above)
Thanks again for your new suggestion. Im afraid it didn't work. I copied your last version of the System.config and changed my code to use the import statement with require as you suggested in the first version of your andwer and still got the same xhr error. I also tried: import * as child from "child_process"; That didn't work either with same error. I also tried doing it with the /// reference at the top to the node.d.ts but as I expected it didn't change anything
Maybe also rename the title of the question to "Require nodejs “child_process” with typescript, systemjs and electron".
Glad it was helpful, actually I was not familiar with SystemJS, only the TypeScript and Electron, but I supposed the problem was, that SystemJS was loading nodejs module as regular browser dependency. So at first I suggested to map it somehow to CommonJS module name pattern. When that no helped I just looked into the source code to understand how actually the mapping works, and saw that it was this @node prefix required. Yes, It should be documented, but you can always take a look into the source codes, so you can understand how the library was "designed"). Cheers
|
11

If the error message is Cannot find module 'child_process' or its corresponding type declarations the answer is npm install @types/node

Comments

5

For me it worked with the callback to display the results.

import * as child from 'child_process';

 var foo: child.ChildProcess = child.exec('dir', (error: string, stdout: string, stderr: string) => {
            console.log(stdout);      
        });

I didn't add any mappings in SystemJS as I dont have any such configuration in the node application

Comments

4

Me & Bing chat:

import { exec } from "child_process";

function openBrowser(url) {
  // Get the operating system
  const os = process.platform;

  // Choose the command based on the operating system
  let cmd;
  if (os === "win32") {
    // Windows
    cmd = `start ${url}`;
  } else if (os === "darwin") {
    // Mac OS
    cmd = `open ${url}`;
  } else if (os === "linux") {
    // Linux
    cmd = `xdg-open ${url}`;
  } else {
    // Unsupported OS
    throw new Error("Unsupported operating system");
  }

  // Execute the command
  exec(cmd, (error, stdout, stderr) => {
    if (error) {
      console.error(`Failed to open browser: ${error.message}`);
      return;
    }
    if (stderr) {
      console.error(`Error: ${stderr}`);
      return;
    }
    console.log(`Opened browser: ${stdout}`);
  });
}

// Example usage
openBrowser("https://www.google.com");

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.