Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript error for "app.ws" using express-ws

In my small project, I want to build a BabyCam that can be accessed from any web browser using a Raspberry Pi Zero. For this, I would like to open a web socket using express-is to stream video to several clients. I am basing most of the video-related code on the raspivid-stream module. However, when trying to access the web socket, I get a type error for app.ws(... stating Property 'ws' does not exist on type 'Application'. Of course, I imported both the typings for express and express-ws.

I am not really sure, what the problem is as the same call in JavaScript appears work fine. Here's the code - I am glad for any help!

import express from 'express';
import { Request, Response } from 'express';
import fs from 'fs';
import https from 'https';
import http from 'http';
import raspividStream from 'raspivid-stream';
import expressWs from 'express-ws';


const server: express.Application = express();

const httpPort: number = 8080;
const httpsPort: number = 8443;

const sslCredentials = {
    key: fs.readFileSync('../ssl/localhost.key', 'utf8'),
    cert: fs.readFileSync('../ssl/localhost.cert', 'utf8')
};

// CREATE SERVER

const httpServer = http.createServer(server);
const httpsServer = https.createServer(sslCredentials, server);

expressWs(server, httpsServer);

// ROUTES

server.get('*', (req: Request, res:Response) => {
    if (!req.secure) {
        return res.redirect(`https://${req.hostname}:${httpsPort}${req.originalUrl}`);
    }
    res.sendFile(__dirname + '/client/index.html');
});

// WEBSOCKET

server.ws('/video-stream', (ws) => {
    console.log('Client connected');


    ws.send(JSON.stringify({
    action: 'init',
    width: '960',
    height: '540'
    }));

    var videoStream = raspividStream({ rotation: 180 });

    videoStream.on('data', (data) => {
        ws.send(data, { binary: true }, (error) => { if (error) console.error(error); });
    });

    ws.on('close', () => {
        console.log('Client left');
        videoStream.removeAllListeners('data');
    });
});


// START SERVER

httpServer.listen(httpPort, () => {
    console.log(`BabyCam (redirect) listening at http://localhost:${httpPort}/`);
}); 

httpsServer.listen(httpsPort, () => {
    console.log(`BabyCam (SSL) listening at https://localhost:${httpsPort}/`);
});
like image 867
Burney Avatar asked Sep 20 '25 15:09

Burney


1 Answers

Property 'ws' does not exist on type 'Application' is a typescript error, indicating that typescript is not aware of a ws() method on app. This is expected because ws() is not a part of the default express API, and so the TS types (@types/express) don't define it.

The ws() method comes from the express-ws module as a "mix in". The express-ws types (@types/ws-express) do define this, but the code needs to be structured to allow Typescript to be aware of this ...

First, make sure you have TS types for express and express-ws installed:

npm install @types/express @types/express-ws

Then create server as follows:

const expressServer = express();           // Type = Express 
const wsServer = expressWs(expressServer); // Type = expressWs.Instance
const server = wsServer.app;               // type = wsExpress.Application

Defining the code in this way gives server the expressWs.Application type, defined here (which includes the WithWebsocketMethod declaration for ws() here)

NOTE: The runtime value of server and expressServer is identical at runtime. It's the same exact Express instance (which is why your code works fine when run as plain JS). We're just handling things slightly differently to keep Typescript informed of what's happening with the types.

like image 157
Mathieu CAROFF Avatar answered Sep 22 '25 09:09

Mathieu CAROFF