react-console-emulator icon indicating copy to clipboard operation
react-console-emulator copied to clipboard

typescript support?

Open 18601673727 opened this issue 5 years ago • 16 comments
trafficstars

Good job!

18601673727 avatar Nov 29 '19 10:11 18601673727

I haven’t used TypeScript awfully much, what’s the current bugbear against using this with it? I’d be glad to support it though!

linuswillner avatar Nov 30 '19 20:11 linuswillner

Well, it simply gives this error after following the directions from README:

index.js:1 ERROR in /Users/me/project/pages/admin/queue.tsx
6:22 Could not find a declaration file for module 'react-console-emulator'. '/Users/me/project/node_modules/react-console-emulator/lib/components/Terminal.js' implicitly has an 'any' type.
  Try `npm install @types/react-console-emulator` if it exists or add a new declaration (.d.ts) file containing `declare module 'react-console-emulator';`
    4 | import { useHarmonicIntervalFn } from 'react-use'
    5 | import { Pane, PaneBody, PaneHead } from '@components/admin/PaneView'
  > 6 | import Terminal from 'react-console-emulator'
      |                      ^
    7 | import * as Space from 'react-spaces'
    8 | 
    9 | const Style = styled.div`

18601673727 avatar Nov 30 '19 20:11 18601673727

Ah, so I have to provide a type declaration for it, gotcha. I’ll implement that as soon as possible, but if you’re in a rush, you could always monkey-patch it for the time being. Thanks for the report!

linuswillner avatar Nov 30 '19 20:11 linuswillner

Temporary solution for this is creating a declaration.d.ts file in your src folder and declaring a module and exporting the Terminal.

declare module 'react-console-emulator' {
  export default Terminal;
}

Fronix avatar Mar 06 '20 06:03 Fronix

After some consideration, I'm potentially going to convert this library to TypeScript entirely at some point in the future. However, for now, maintaining duplicate type declarations is not something I'm going to start doing, since I already have one set to maintain with prop-types and maintaining both is just not really all that feasible. You folks using TS will have to get by with declaring custom types for a while to come.

Labeling this issue as deferred for now to kick the can down the road for the eventual TS rewrite. I'll leave it open however.

linuswillner avatar Apr 22 '20 22:04 linuswillner

Hi @linuswillner,

Thanks for the great library! I miss the type definitions and I'd be happy to help to convert the package to TypeScript.

The library seems to be small enough, so it won't take too long to do it and review it. Also, it would allow removing almost all checks from the validateCommands function. I saw the package has tests, so you'll be able to validate everything works as expected.

If you're worried about maintaining both TypeScript types and prop-types, babel-plugin-typescript-to-proptypes would probably help

Please let me know if you're interested in a pull request

kulyk avatar Apr 26 '20 05:04 kulyk

For now, if you want to use react-console-emulator in your TypeScript project, you need to write a module declaration yourself. I've already done it, you can reuse my solution.

  1. Install csstype
  2. Create a global.d.ts file in your project root
  3. Paste the next declaration there
declare module 'react-console-emulator' {
  import * as React from 'react';
  import * as CSS from 'csstype';

  interface OptionProps {
    autoFocus: boolean;
    dangerMode: boolean;
    disableOnProcess: boolean;
    noDefaults: boolean;
    noAutomaticStdout: boolean;
    noHistory: boolean;
    noAutoScroll: boolean;
  }

  interface LabelProps {
    welcomeMessage: boolean | string | string[];
    promptLabel: string;
    errorText: string;
  }

  interface CommandProps {
    commands?: {
      description: string;
      usage?: string;
      fn: () => string;
    };
    commandCallback?: () => {};
  }

  export type TerminalProps = CommandProps &
    LabelProps &
    OptionProps &
    StyleProps;

  export default class Terminal extends React.Component<TerminalProps, {}> {}
}

kulyk avatar Apr 26 '20 06:04 kulyk

Hi @kulyk, thanks for the brilliant suggestions! A few things here.

First of all, I really appreciate the offer to help out in the TypeScript conversion! I’ll be sure to get back to you when that’s relevant - however, I’m currently working on a major overhaul of the library on the v4 branch, and I think it’s best if I complete that overhaul before I start considering the TS conversion, hence (partly) my reasoning to defer the conversion until later.

Second, as for being able to get rid of validateCommands, I do want this library to continue functioning identically in vanilla JavaScript even after it’s converted to TypeScript, meaning that I have to consider keeping those checks if necessary. If it becomes apparent that they can be removed entirely, I will do that in that event. I’ll have to re-evaluate this better later, as explained above.

Lastly, big thanks for the excellent solution recommendation and sharing your typings! I’ll be sure to keep these in mind as well for the future.

Top job there, thanks a bunch.

linuswillner avatar Apr 26 '20 10:04 linuswillner

  1. Oh, cool! Didn't know about that
  2. Yes, you're right, it would be a more safe solution for vanilla JS without type checks

Feel free to ping me in this thread later, I'll be happy to help

kulyk avatar Apr 26 '20 10:04 kulyk

Any progress on this regards?

staminna avatar Jun 16 '22 19:06 staminna

I am more than willing to also help out with this endeavor. I already looked at the source code and made webpack build system work with typescript, if you want the code, just ask me.

BjornTheProgrammer avatar Aug 21 '22 06:08 BjornTheProgrammer

I think I do but, will I be able to run commands on the node.js backend from a websocket such as socket.io?

staminna avatar Aug 23 '22 07:08 staminna

@staminna Yes, I'm doing so right now actually.

BjornTheProgrammer avatar Aug 23 '22 14:08 BjornTheProgrammer

@staminna Here is the method with a nodejs backend

Server

io.on('connection', (socket: Socket) =>{
	socket.on('clear', (params, callback) => {

		// send data back to client by using emit
		socket.emit('clear');

		// broadcasting data to all other connected clients
		socket.broadcast.emit('clear');
	})
})

Client

class App extends Component<props, state> {
	terminal: any = React.createRef();

	componentDidMount() {
		socket.on("clear", () => {
			console.log("recieved clear");
			this.terminal.current.clearInput();
			this.terminal.current.terminalInput.current.value = "clear";
			this.terminal.current.processCommand();
		})
	}

	componentWillUnmount() {
		socket.off('clear');
	}

	render() {
		return ...
	}
}

If you want to run some code on the node js backend, you can do the following instead. Server

socket.on('pull', (params, callback) => {
	console.log("getting pull")

	// broadcasting data to all other connected clients
	socket.broadcast.emit('pull');

	try {
		if (fs.existsSync(gitDir)) {
			fs.rmSync(gitDir, { recursive: true });
		}

		fs.mkdirSync(gitDir);

		const options = {
			baseDir: gitDir,
		};

		simpleGit(options).clean(CleanOptions.FORCE);

		const remote = config.gitRepository;

		simpleGit()
			.clone(remote)
			.then(() => {
				socket.emit('stdout', "Successfully pulled " + config.gitBaseDir + " from github");
				socket.broadcast.emit('stdout', "Successfully pulled " + config.gitBaseDir + " from github");
			}).catch((err) => {
				throw err;
			});

	} catch (error) {
		socket.emit('stdout', "Error attempting to pull the repository");
		socket.broadcast.emit('stdout', "Error attempting to pull the repository");
	}
})

Client

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import constructEcho from 'react-console-emulator/dist/utils/constructEcho';
...
class App extends Component<props, state> {
	terminal: any = React.createRef();

	componentDidMount() {
		socket.on("pull", (gitUrl) => {
			console.log("recieved pull");
			const commandName = "pull"
			this.terminal.current.pushToHistory(commandName)
			this.terminal.current.pushToStdout(constructEcho(this.terminal.current.props.promptLabel || '$', commandName, this.terminal.current.props), { isEcho: true })
		})

		socket.on("stdout", (out) => {
			console.log("recieving stdout");
			console.log("out: ", out);
			this.terminal.current.pushToStdout(out)
		})
	}

	componentWillUnmount() {
		socket.off('pull');
		socket.off('stdout');
	}

	commands = {
		pull: {
			description: 'Does a git pull to update the current repository on server',
			fn: () => {
				socket.emit("pull");
			}
		},
	}

	render() {
		return ...
	}
}

You can see my attempted implementation in my repository BDOS-Online (name soon to change to BREDOS-Online) under the socket-io branch if you want to look further.

BjornTheProgrammer avatar Aug 23 '22 14:08 BjornTheProgrammer

Does react-console-emulator currently support typescript? Is there any latest progress?

resetsix avatar Mar 19 '24 07:03 resetsix

@resetsix any javascript code supported in typescript

Check this comment https://github.com/linuswillner/react-console-emulator/issues/416#issuecomment-619490463 I just used it and it works

im7mortal avatar May 24 '24 13:05 im7mortal