Skip to content

Latest commit

 

History

History
171 lines (134 loc) · 4.78 KB

typescript.md

File metadata and controls

171 lines (134 loc) · 4.78 KB
execa logo

🤓 TypeScript

Available types

The following types can be imported: ResultPromise, Subprocess, Result, ExecaError, Options, StdinOption, StdoutStderrOption, TemplateExpression and Message.

import {
	execa,
	ExecaError,
	type ResultPromise,
	type Result,
	type Options,
	type StdinOption,
	type StdoutStderrOption,
	type TemplateExpression,
	type Message,
} from 'execa';

const options: Options = {
	stdin: 'inherit' satisfies StdinOption,
	stdout: 'pipe' satisfies StdoutStderrOption,
	stderr: 'pipe' satisfies StdoutStderrOption,
	timeout: 1000,
	ipc: true,
};
const task: TemplateExpression = 'build';
const message: Message = 'hello world';

try {
	const subprocess: ResultPromise = execa(options)`npm run ${task}`;
	await subprocess.sendMessage(message);
	const result: Result = await subprocess;
	console.log(result.stdout);
} catch (error) {
	if (error instanceof ExecaError) {
		console.error(error);
	}
}

Synchronous execution

Their synchronous counterparts are SyncResult, ExecaSyncError, SyncOptions, StdinSyncOption, StdoutStderrSyncOption and TemplateExpression.

import {
	execaSync,
	ExecaSyncError,
	type SyncResult,
	type SyncOptions,
	type StdinSyncOption,
	type StdoutStderrSyncOption,
	type TemplateExpression,
} from 'execa';

const options: SyncOptions = {
	stdin: 'inherit' satisfies StdinSyncOption,
	stdout: 'pipe' satisfies StdoutStderrSyncOption,
	stderr: 'pipe' satisfies StdoutStderrSyncOption,
	timeout: 1000,
};
const task: TemplateExpression = 'build';

try {
	const result: SyncResult = execaSync(options)`npm run ${task}`;
	console.log(result.stdout);
} catch (error) {
	if (error instanceof ExecaSyncError) {
		console.error(error);
	}
}

Type inference

The above examples demonstrate those types. However, types are automatically inferred. Therefore, explicit types are only needed when defining functions that take those values as parameters.

import {
	execa,
	ExecaError,
	type Result,
} from 'execa';

const printResultStdout = (result: Result) => {
	console.log('Stdout', result.stdout);
};

const options = {
	stdin: 'inherit',
	stdout: 'pipe',
	stderr: 'pipe',
	timeout: 1000,
	ipc: true,
} as const;
const task = 'build';
const message = 'hello world';

try {
	const subprocess = execa(options)`npm run ${task}`;
	await subprocess.sendMessage(message);
	const result = await subprocess;
	printResultStdout(result);
} catch (error) {
	if (error instanceof ExecaError) {
		console.error(error);
	}
}

Troubleshooting

Supported version

The minimum supported TypeScript version is 5.1.6.

ES modules

This package uses pure ES modules. Therefore the TypeScript's --module compiler option must be set to nodenext or preserve. More info.

Otherwise, transpilation will work, but running the transpiled file will throw the following runtime error:

Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported.

Or:

ReferenceError: exports is not defined in ES module scope

Strict unions

Several options are typed as unions. For example, the serialization option's type is 'advanced' | 'json', not string. Therefore the following example fails:

import {execa} from 'execa';

// Type error: "No overload matches this call"
const spawnSubprocess = (serialization: string) => execa({serialization})`npm run build`;

// Without `as const`, `options.serialization` is typed as `string`, not `'json'`
const options = {serialization: 'json'};
// Type error: "No overload matches this call"
await execa(options)`npm run build`;

But this works:

import {execa, type Options} from 'execa';

const spawnSubprocess = (serialization: Options['serialization']) => execa({serialization})`npm run build`;

const options = {serialization: 'json'} as const;
await execa(options)`npm run build`;

Next: 📔 API reference
Previous: 🔍 Differences with Bash and zx
Top: Table of contents