Sendgrid-nodejs: Cannot import type definitions from `@sendgrid/mail`

Created on 6 Apr 2018  ·  7Comments  ·  Source: sendgrid/sendgrid-nodejs

Issue Summary

I cannot import and use the type definitions from @sendgrid/mail with TS v2.8.1. Very likely that I've just misunderstood, but have tried a few things after reading the index.d.ts.

Seems the type I would like is MailService & { MailService: MailService; }, so says tsc if I try to arbitrarily assert something like:

SendGrid.setApiKey('blahblah')
export default Sendgrid as SomethingElse

Steps to Reproduce

Doesn't work:

import SendGrid = require('@sendgrid/mail')

interface Foo {
  mail: Sendgrid.MailService // [ts] Cannot find namespace 'Sendgrid'
}

Also doesn't work:

import { MailService } from '@sendgrid/mail'

interface Foo {
  mail: MailService // [ts] Cannot find name 'MailService'
}

Technical details:

  • sendgrid-nodejs: v6.2.1
  • typescript: v2.8.1
  • node: v9.6.1

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "./",
    "module": "commonjs",
    "outDir": "dist",
    "sourceMap": true,
    "strict": true,
    "target": "es6",

    "paths": {
      "@/*": ["src/*"]
    }
  }
}

Mentioned this in #476 - thought it might be related.

unknown or a help wanted help wanted question up for grabs up-for-grabs

Most helpful comment

Hi @killtheliterate,

Can you let me know if this works for you?

import * as SendGrid from "@sendgrid/mail";
SendGrid.setApiKey("blahblah")

interface Foo {
    mail: typeof SendGrid.MailService
}

const foo: Foo = {
    mail: SendGrid
}

export = foo

It appears to work fine locally for me, the big difference being the use of the typeof keyword when referencing the MailService type within your interface.

All 7 comments

@SPARTAN563,

Any ideas?

Hi @killtheliterate,

Can you let me know if this works for you?

import * as SendGrid from "@sendgrid/mail";
SendGrid.setApiKey("blahblah")

interface Foo {
    mail: typeof SendGrid.MailService
}

const foo: Foo = {
    mail: SendGrid
}

export = foo

It appears to work fine locally for me, the big difference being the use of the typeof keyword when referencing the MailService type within your interface.

@SPARTAN563 that does the trick, thank you! Is there a link you could toss me that explains why the typeof is necessary?

Great!

The reason why the original version ({ mail: SendGrid.MailService }) doesn't work is that you're attempting to treat a value as a type. The typeof operator transforms that value into a type which can then be used within the type system to build the constraint you're looking for.

Take the following example:

const X = {
  x: String
}

interface Y {
  y: X.x
}

Looking at that, you'd probably expect it not to work since you're trying to constrain a type based on the value of a const object ({ x: String }). However to accomplish what is implied by that example, you could ask TypeScript to constrain based on the type of the value, in this case:

const X = {
  x: String
}

interface Y {
  y: typeof X.x // String
}

Exactly the same thing is at play here due to the gymnastics we had to perform to represent the library's interface in TypeScript. Unfortunately libraries that make use of the old NodeJS module.exports = X export format will continue to encounter problems like this and while we can work around it with virtual namespaces and XConstructor interfaces, it generally isn't worth it and leads to even more confusion.

I hope that explains what's going on and why, but please feel free to ask if you've got any other questions or if my explanation isn't clear.

@SPARTAN563 thanks so much for the explanation!

Good evening,

My app is on firebase (node.js), and I had the same problem.

I changed the way I imported @sendgrid

I also set up single sender verification on app.sendgrid.com.

Before:
const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);

After:
import * as SendGrid from "@sendgrid/mail";
const SENDGRID_API_KEY = functions.config().sendgrid.key

SendGrid.send(msg).then( snapshotMail => {
  console.log("Passou D")
  console.log("Sucesso")
  console.log(snapshotMail[0])
  console.log(snapshotMail[1])
}).catch((e)=> console.error(e.message));

@dougadriquei I'm having the same problem, but import * as SendGrid from "@sendgrid/mail"; doesn't work for me and results in TypeError: s.setApiKey is not a function. So I have to use import SendGrid ... normally, and when console.logging the functions are there as expected.
I'm on CloudFlare workers. It works on Nodejs as expected :confused:

According to SendGrid's docs Single Sender Verification doesn't apply to me.

Turns out import * as doesn't matter it's just peculiarity of esModuleInterop being set to true, once set back to false and import being import * as it still doesn't work :confused:

Was this page helpful?
0 / 5 - 0 ratings