hagenek
hagenek

Reputation: 118

How to fix compiler error for std module dependency in Deno program?

I know there is a question with the same error on SO, but the answer there doesnt help me: deno bundle failed. Property 'getIterator' does not exist on type 'ReadableStream<R>'

Here is the full error:

❯ deno run --allow-all server.ts Check file:///Users/hagenek/repos/mock-backend/server.ts error: TS2339 [ERROR]: Property 'getIterator' does not exist on type 'ReadableStream'. return res.readable.getIterator(); ~~~~~~~~~~~ at https://deno.land/[email protected]/async/pool.ts:45:23

Here is my server.ts code:

import { Application } from "./deps.ts";
import router from "./routes.ts"
const PORT = 4000;
const app = new Application();

app.use(router.routes()); // Pass our router as a middleware
app.use(router.allowedMethods()); // Allow HTTP methods on router

await app.listen({ port: PORT });
console.log(`Server running on PORT: ${PORT}`)

Routes.ts:

import { Router } from "https://deno.land/x/oak/mod.ts";
import {
    addQuote,
    getQuotes,
    getQuote,
    updateQuote,
    deleteQuote,
} from "./controllers/controller.ts";

interface ReadableStream<R> {
    getIterator(): any
}

const router = new Router(); // Create Router

    router
        .get("/api/quote", getQuotes) // Get all quotes
        .get("/api/quote/:id", getQuote) // Get one quote of quoteID: id
        .post("/api/quote", addQuote) // Add a quote
        .put("/api/quote/:id", updateQuote) // Update a quote
        .delete("/api/quote/:id", deleteQuote); // Delete a quote
    
    export default router;

Deps.ts

export {
    Application
} from "https://deno.land/x/oak/mod.ts"

Controller.ts

interface Quote {
    _id: { $oid: string };
    quote: string;
    quoteID: string;
    author: string;
}

import {MongoClient} from "https://deno.land/x/[email protected]/mod.ts";

const URI = "mongodb://127.0.0.1:27017";

// Mongo Connection Init
const client = new MongoClient();
try {
    await client.connect(URI);
    console.log("Database successfully connected");
} catch (err) {
    console.log(err);
}

const db = client.database("quotesApp");
const quotes = db.collection<Quote>("quotes");

// DESC: ADD single quote
// METHOD: POST /api/quote
export const addQuote = async ({request, response,}: {
    request: any;
    response: any;
}) => {
    try {
        // If the request has no Body, it will return a 404
        if (!request.hasBody) {
            response.status = 400;
            response.body = {
                success: false,
                msg: "No Data",
            };
        } else {
            // Otherwise, it will try to insert
            // a quote in the DB and respond with 201
            const body = await request.body();
            const quote = await body.value;
            await quotes.insertOne(quote);
            response.status = 201;
            response.body = {
                success: true,
                data: quote,
            };
        }
    } catch (err) {
        response.body = {
            success: false,
            msg: err.toString(),
        };
    }
};

// DESC: GET single quote
// METHOD: GET /api/quote/:id
export const getQuote = async ({
                            params,
                            response,
                        }: {
    params: { id: string };
    response: any;
}) => {
    // Searches for a particular quote in the DB
    const quote = await quotes.findOne({quoteID: params.id});
    // If found, respond with the quote. If not, respond with a 404
    if (quote) {
        response.status = 200;
        response.body = {
            success: true,
            data: quote,
        };
    } else {
        response.status = 404;
        response.body = {
            success: false,
            msg: "No quote found",
        };
    }
};

// DESC: GET all Quotes
// METHOD GET /api/quote
export const getQuotes = async ({response}: { response: any }) => {
    try {
        // Find all quotes and convert them into an Array
        const allQuotes = await quotes.find({}).toArray();
        console.log(allQuotes);
        if (allQuotes) {
            response.status = 200;
            response.body = {
                success: true,
                data: allQuotes,
            };
        } else {
            response.status = 500;
            response.body = {
                success: false,
                msg: "Internal Server Error",
            };
        }
    } catch (err) {
        response.body = {
            success: false,
            msg: err.toString(),
        };
    }
};

// DESC: UPDATE single quote
// METHOD: PUT /api/quote/:id
export const updateQuote = async ({
                               params,
                               request,
                               response,
                           }: {
    params: { id: string };
    request: any;
    response: any;
}) => {
    try {
        // Search a quote in the DB and update with given values if found
        const body = await request.body();
        const inputQuote = await body.value;
        await quotes.updateOne(
            { quoteID: params.id },
            { $set: { quote: inputQuote.quote, author: inputQuote.author } }
        );
        // Respond with the Updated Quote
        const updatedQuote = await quotes.findOne({ quoteID: params.id });
        response.status = 200;
        response.body = {
            success: true,
            data: updatedQuote,
        };
    } catch (err) {
        response.body = {
            success: false,
            msg: err.toString(),
        };
    }
};


// DESC: DELETE single quote
// METHOD: DELETE /api/quote/:id
export const deleteQuote = async ({
                               params,
                               response,
                           }: {
    params: { id: string };
    request: any;
    response: any;
}) => {
    try {
        // Search for the given quote and drop it from the DB
        await quotes.deleteOne({quoteID: params.id});
        response.status = 201;
        response.body = {
            success: true,
            msg: "Product deleted",
        };
    } catch (err) {
        response.body = {
            success: false,
            msg: err.toString(),
        };
    }
};

Upvotes: 3

Views: 1397

Answers (1)

jsejcksn
jsejcksn

Reputation: 33881

The problem

You are using an outdated version of deno.land/x/mongo (v0.22.0, whose dependencies are also outdated and misaligned with Deno's current built-in type libraries).

The solution

Use a version of the module which is compatible with the version of Deno that you are using.

At the time of writing this answer, Deno stable is at v1.16.3, and the latest version of that module is v0.28.0: https://deno.land/x/[email protected]. They appear to be compatible.

Explanation

Here's the compiler error from your module:

% deno cache server.ts 
Check file:///Users/deno/so-70169022/server.ts
error: TS2339 [ERROR]: Property 'getIterator' does not exist on type 'ReadableStream<R>'.
  return res.readable.getIterator();
                      ~~~~~~~~~~~
    at https://deno.land/[email protected]/async/pool.ts:45:23

For reference, here's the version of Deno I'm using:

% deno --version
deno 1.16.3 (release, x86_64-apple-darwin)
v8 9.7.106.5
typescript 4.4.2

You can see that the error happens in the module at https://deno.land/[email protected]/async/pool.ts (which, unfortunately, you can't edit to fix the problem). Note that it's a module from the std library (I'll come back to this).

Here's the module graph for your entrypoint:

Note: I've removed all of the lines in the output unrelated to the problematic module in order to improve readability

% deno info server.ts
local: /Users/deno/so-70169022/server.ts
type: TypeScript
dependencies: 134 unique (total 1.72MB)

file:///Users/deno/so-70169022/server.ts (334B)
└─┬ file:///Users/deno/so-70169022/routes.ts (638B)
  └─┬ file:///Users/deno/so-70169022/controllers/controller.ts (4.24KB)
    └─┬ https://deno.land/x/[email protected]/mod.ts (113B)
      └─┬ https://deno.land/x/[email protected]/deps.ts (783B)
        └─┬ https://deno.land/[email protected]/node/_crypto/pbkdf2.ts (4.18KB)
          └─┬ https://deno.land/[email protected]/node/buffer.ts (15.46KB)
            └─┬ https://deno.land/[email protected]/node/_utils.ts (5.74KB)
              └─┬ https://deno.land/[email protected]/async/mod.ts (202B)
                └── https://deno.land/[email protected]/async/pool.ts (1.58KB)

The problematic module is at the bottom of a series of nested imports from the std library, which lead up to mongo/deps.ts and mongo/mod.ts, which is being imported by ./controllers/controller.ts (which is the first module that you can directly edit to fix the problem).

Now I'll pause for a moment to revisit std modules:

At https://deno.land/[email protected]#releases it says this:

Standard library is currently tagged independently of Deno version. This will change once the library is stabilized.

To check compatibility of different version of standard library with Deno CLI see this list.

What this means is that each version of the std library is only guaranteed to be compatible with a specific version of Deno.

The version of the std library currently being used by the mongo module in your program is v0.83.0, and, referencing the linked compatibility JSON list above, you can find that it maps to Deno v1.6.3 (which is quite old).

At this point, your most accessible options are:

  1. to use a version of Deno compatible with that version of the mongo module (using an old version of Deno is probably not the best idea), or

  2. to use a version of the mongo module which is compatible with a newer version of Deno (let's try this one first)

Let's see what the latest version of the mongo module is:

https://deno.land/x/[email protected]/deps.ts is the latest version right now, and it uses v0.111.0 of the std library.

Let's try updating the version of the mongo module in your program and see if it fixes the compiler error:

./controllers/controller.ts (line 8):

// before:
// import {MongoClient} from "https://deno.land/x/[email protected]/mod.ts";

// after:
import {MongoClient} from "https://deno.land/x/[email protected]/mod.ts";

Now let's type check and cache your entrypoint again:

% deno cache server.ts

No compiler error this time! 🏆

Upvotes: 5

Related Questions