Ask coding questions

← Back to all posts
TypeScript Cannot find name for 'JSON'
mwilki7 (280)

I'm attempting to get a simple NodeJS server programmed in TypeScript to send a client a json string but I get this error message:

index.ts:17
app.get('/', function (req : any, res : any)
                                              ^
TypeError: Converting circular structure to JSON
    at JSON.stringify (<anonymous>)
    at Socket.<anonymous> (index.ts:17:47)
    at Socket.emit (events.js:198:13)
    at Socket.EventEmitter.emit (domain.js:448:20)
    at /home/runner/node_modules/socket.io/lib/socket.js:528:12
    at process._tickCallback (internal/process/next_tick.js:61:11)

Also, another error message appears under all lines that say 'JSON'


According to :
https://github.com/TypeStrong/atom-typescript/issues/1211
it says this issue is supposed to be fixed if JSON is the one causing the problem.

Anyone know what's wrong with the program?

Answered by Klokat (41) [earned 5 cycles]
View Answer
Commentshotnewtop
Klokat (41)

The first error happens because there's no way for json to stringify a circular object as it says.
Ask yourself this how would you represent a as a string?

var a = {};
var b = { a: a};
a.b = b;
// '{ "b": { "a": { "b": { "a": {... and so on forever

There's something similar within the canvas object.
If you want to transfer the image of the canvas you could call ctx.getImageData(0, 0, canvas.width, canvas.height) and transfer that instead. Then call ctx.putImageData(data, x, y); on the client/browser.

As a side thing here is why there's a circular reference in that npm package (or at least one of the cases where there's one):
https://github.com/Automattic/node-canvas/blob/master/lib/canvas.js#L26

this.context = ctx;
ctx.canvas = this;

Which means something like this:

canvas.context.canvas.context.canvas.context.fillRect(0, 0, 100, 100);

would be valid with this package.

As for the second problem I really have no idea. Cheers

mwilki7 (280)

@Klokat Is this a typescript thing? I have other non-typescript programs where I've successfully stringified canvas data and sent it over sockets.

Klokat (41)

@mwilki7 I don't think it's a typescript thing since the node-canvas is a javascript package. Were the canvas object you stringified in the past using the same library? I'd love to see a project in which this worked so we could figure out what changed.

mwilki7 (280)

@Klokat I have something similar going on in
https://repl.it/@mwilki7/Telestrations-Server2
But the client is the one doing the JSON stringifying.
an example:

        $('#cloneButton').click(function ()
        {
            var message = { type: msgType.IMG, data: JSON.stringify(canvas) };
            socket.emit('sendchat', message);
        }); 
Klokat (41)

@mwilki7 I think this was possible because it was Canvas object from fabric.js library. And that object is serializable by design. JSON.stringify(document.createElement('canvas')) returns {} in the browser.

Klokat (41)

@mwilki7 I forgot to mention in the first comment that you'll probably want to JSON.stringify the object returned by getImageData.

mwilki7 (280)

@Klokat I've changed my image parsing function to:
client:

function redrawCanvas(data)
{
    imgdata = JSON.parse(data);
    ctx.putImageData(imgdata, 0, 0);
}

Looks like JSON might have added a bit too much fluff or I'm doing it wrong:

Klokat (41)

@mwilki7 Alright this might be getting a bit complicated here and inefficient but try this:

In the server

var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = JSON.stringify({
  'array': Array.from(imageData.data),
  'width': imageData.width
});
// Emit data

In the client

var obj = JSON.parse(data);
var colorData = new Uint8ClampedArray(obj.array);
var imageData = new ImageData(colorData, obj.width);
ctx.putImageData(imageData, 0, 0);

Sorry if there's a syntax error I didn't try running this.
The reason I'm calling Array.from(imageData.data) is because imageData.data is of type Uint8ClampedArray and JSON.stringify treats it like an object and not an array.
I'm also not sending ImageData as this will lose it's type when you serialize/stringify it. Instead I'm sending an object with the an array of pixels and the width of the image. Which on the client I use to construct in ImageData object with the pixel data and the width.

This whole back and forth with the data is probably not efficient but it should work. Hopefully.

mwilki7 (280)

@Klokat No error messages except

I'll comment out the socket sending to see if it still persists.

edit: actually just had to restart the server, but the circular structure to JSON message came back

If worse comes to worst I'll just get a png version of the canvas and send that instead.

Klokat (41)

@mwilki7 That's odd, is it this

var data = JSON.stringify({
  'array': Array.from(imageData.data),
  'width': imageData.width
});

that throws the circular structure error thing?

Could it be line 28 var data : string = JSON.stringify(ctx.getImageData(0, 0, canvas.width, canvas.height)); that's the problem? Cause you didn't comment the old lines out in your repl.

mwilki7 (280)

@Klokat whoops
must have uncommented the wrong lines
Ok, so the circular structure problem has gone away, but this


has returned. Thanks for sticking with me this long, by the way. I was afraid I was going to have to send canvas data bit by bit or something.

Klokat (41)

@mwilki7 Honestly I have no idea why that happens. It happened to me a couple of times. But it fixed itself? I have no idea.
https://repl.it/@Klokat/TypeScriptTesting-Works
Try it here. You'll need a font to render text from the server because as far as I can tell the instance that repl.it serves doesn't come with fonts. But I'm getting this

so it's probably alright.

mwilki7 (280)

@Klokat Cursed default font properties. Thanks for all your help and doing some debugging for me.