Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve typescript types #144

Open
StarpTech opened this issue Aug 25, 2020 · 10 comments
Open

Improve typescript types #144

StarpTech opened this issue Aug 25, 2020 · 10 comments
Labels
good first issue Good for newcomers

Comments

@StarpTech
Copy link
Member

馃殌 Feature Proposal

  • Some interfaces aren't covered e.g onFile handler in the new promise API.
  • Validate TS types in the CI.

Motivation

Full TS support.

@StarpTech StarpTech added the good first issue Good for newcomers label Aug 25, 2020
mcollina pushed a commit that referenced this issue Sep 3, 2020
* Update MultipartFields

If the field names are the same, the value of the field will be an array.

* Add tests

* Update more definitions

* Update onFile handler (#144)

* Update index.d.ts

Co-authored-by: Maksim Sinik <maksim@sinik.it>

Co-authored-by: Maksim Sinik <maksim@sinik.it>
@nadhifikbarw
Copy link
Contributor

nadhifikbarw commented Mar 12, 2023

Would maintainer okay with the idea of adding one extra property? I'm thinking type with literal string as value, for both MultipartFile with value ("file") and MultipartValue with value ("field") to make type narrowing feel more intuitive.

Use case: https://github.com/fastify/fastify-multipart#handle-multiple-file-streams-and-fields

fastify.post('/upload/raw/any', async function (req, reply) {
  const parts = req.parts()
  for await (const part of parts) {
    if (part.file) {  // Failed type narrowing
      await pump(part.file, fs.createWriteStream(part.filename))
    } else {
      console.log(part)
    }
  }
  reply.send()
})

However

fastify.post('/upload/raw/any', async function (req, reply) {
  const parts = req.parts()
  for await (const part of parts) {
    if ("file" in part) {  // Success type narrowing
      await pump(part.file, fs.createWriteStream(part.filename))
    } else {
      console.log(part)
    }
  }
  reply.send()
})

I feel like having type property would feel more intuitive. It would look like:

fastify.post('/upload/raw/any', async function (req, reply) {
  const parts = req.parts()
  for await (const part of parts) {
    if (part.type === 'file') {  // Using discriminated unions
      await pump(part.file, fs.createWriteStream(part.filename))
    } else {
      console.log(part)
    }
  }
  reply.send()
})

Alternative, expose isFilePart as type predicate, but i felt this bit too much.

function isFilePart(part: Multipart): part is MultipartFile {
  return (part as MultipartFile).file !== undefined;
}

fastify.post('/upload/raw/any', async function (req, reply) {
  const parts = req.parts()
  for await (const part of parts) {
    if (isFilePart(part)) {  // Using discriminated unions
      await pump(part.file, fs.createWriteStream(part.filename))
    } else {
      console.log(part)
    }
  }
  reply.send()
})

@mcollina
Copy link
Member

Sure!

@jsjoeio
Copy link

jsjoeio commented Mar 18, 2023

I spent a lot of time trying to make TypeScript to be happy with me using req.file in my router handler. The solution ended up being adding fastify.d.ts with this:

import { Readable } from "stream";
declare module "fastify" {
  export interface FastifyRequest {
    file: () => Promise<{
      file: Readable;
      fieldname: string;
      filename: string;
      encoding: string;
      mimetype: string;
      fields: { [key: string]: string };
    }>;
  }
}

and then including that file in my typeRoots in my tsconfig.json:

{
  "compilerOptions": {
    "typeRoots": ["fastify.d.ts"]
  },
}

Posting here in case it helps others.

@gurgunday
Copy link
Member

Would you like to send a PR?

@jsjoeio

@jsjoeio
Copy link

jsjoeio commented Jan 29, 2024

Sure! I'll see if I can find time this week or next!

@jsjoeio
Copy link

jsjoeio commented Jan 30, 2024

Okay I started looking into this and I'm very confused 馃

Here's a repo.

I thought by installing @fastify/multipart and then registering it like so:

const server = fastify();

server.register(require("@fastify/multipart"));

then TypeScript would pick up the library's types, but if you look here, it doesn't have isMultipart for example (here)

image

So I'm not really sure how to fix (without digging in further). Anyone else have any ideas on what I'm doing wrong? Here's the commit adding multipart

@mcollina
Copy link
Member

Import the module at the top, otherwise TS won't load the declaration merging.

@jsjoeio
Copy link

jsjoeio commented Jan 30, 2024

Import the module at the top, otherwise TS won't load the declaration merging.

馃槄 wow...sorry, totally spaced on that. that fixed and i'm no longer able to reproduce the issue I had before:

diff --git a/index.ts b/index.ts
index 18fe828..9dfc3c7 100644
--- a/index.ts
+++ b/index.ts
@@ -1,4 +1,5 @@
 import fastify from "fastify";
+import "@fastify/multipart";
 
 const server = fastify();
 
@@ -13,7 +14,7 @@ server.post("/upload", async function (req, reply) {
     const data = await req.file();
 
     reply.status(200).send({
-      fileName: data.filename,
+      fileName: data?.filename,
     });
   } catch (error) {
     reply.status(400).send("something went wrong");

@gurgunday should we close this then, or did you have something else in mind for the PR?

@gurgunday
Copy link
Member

I see in the issue description that onFile doesn鈥檛 have corresponding type information

Can you please try adding it?

@jsjoeio
Copy link

jsjoeio commented Mar 25, 2024

I probably won't get to this so anyone else, feel free to take on instead

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

5 participants