19

I'm working on a package that I am planning to publish publicly on npmjs. Let's call it the "text package".

I would like that by default when installing that package, you can import .txt files directly and get the correct type (out of the box), like this:

import text from './file.txt'

The text variable would be of type string because the package would have defined its type, using something like this (in a global.d.ts):

declare module '*.txt' {
    export const text: string;
    export default text;
}

If I include that global.d.ts in my package, and that I import something from this package, then I will automatically get the correct type when importing a .txt file.

But the problem is sometimes I would just need to import a .txt file without importing anything from the "text package", which is why I was wondering if there is some sort of way, as you install a package to install a global type that does not require to import anything else for the type to apply.

In other words, as soon as you install my "txt package" the declare module '*.txt' would apply to my entire project out of the box.

Is there even a way to do this, or whoever installs my package would have to declare their own global type (e.g., declarations.d.ts) to be able to import .txt files globally?

I know that even if the import type works, it will still require Webpack or another bundler to really work but this question is just about the type.

3
  • Would you please sure your package.json file? Commented May 14, 2022 at 2:00
  • This is certainly feasible. I answered your question, but deleted it because it was for the backend. I do this for json files on the backend. I define & declare all the properties that will be in the json file. But I had trouble finding how to declare the the directory, types, as is defined by, "typesRoots": ["./type"] as an internal component on the front end. Commented May 14, 2022 at 21:55
  • Not sure I understand what you mean by backend but basically I am looking for some sort of way to include a type that would be declare global module '*.txt' Commented May 14, 2022 at 22:19

4 Answers 4

10

to bundle global types, do the following. form typescript

  • specify default typings directory at typeRoots. .e.g "typeRoots": ["./src/types"].
  • create a file /src/types/global.d.ts in the specified directory
  • declare your types in the file inside declare global {} and make sure to have export {} if you don't already export anything.
Sign up to request clarification or add additional context in comments.

7 Comments

Yes, this works fine, but unless I am importing the package, it won't inherit the types, which is why I was looking for some sort of global type. I know Next.js does this but it uses npx to create the app which comes with its own global types - I am starting to suspect maybe this is just not feasible using a normal package?
no, I suspect it has anything with npx, please explain this a little bit more here, step by step, after you use npx to init a next.js project. what you that that is possible which is not possible in your created project. I edit the question in case it would still answer the question.
When you run npx create-next-app@latest --ts you can directly import .css files because they implemented CSS modules. You can see their *.css declaration is in a global.d.ts file which is part of their package. By default npx includes a next-end-d.ts which points to the types, but the funny part is that I tried to delete this file and the .css import still works in VS Studio code... I was thinking either this is a glitch in VS code or there is something else I am missing
if updated answer still incorrect, please update again your original question add more replicable details. you can also search for all global.d.ts in you node_modules and check what's defined there
How do you decare a file type module inside a declare global {}? I tried that and I am getting weird errors (like Ambient modules cannot be nested in other modules or namespaces.)
|
7

The short answer is:

TypeScript does not support Global types without importing the file referring to the type.

More details:

One example that I found doing this was Next.js - when creating a TypeScript app using npx create-next-app@latest --typescript you can start importing *.css files (for example) and get the correct type.

Where I got confused is that I originally thought that the type was coming from the next-env.d.ts but even when I deleted the file, *.css import was still working in Visual Studio code. But the reason it was, is because a file in the pages directory were importing Next.js' index.d.ts file.

Basically, in Visual Studio Code, as soon as your import a type somewhere in your project, if it's global, it will be accessible everywhere.

Workaround

So what can be done with the current TypeScript capabilities? To support new file types, you will need a file loader such as Webpack. The logical thing to do would be to add a reference to the file type declaration in the file loader itself. This way, as soon as you configure your file loader to be able to import the file, you will inherit the type:

  1. create a txt.d.ts in our package's source directory (e.g. src) - you can use any name for the file, it's not important
  2. if you are using eslint, add an entry to ignore the type file (e.g. 'src/*.d.ts' in your ignorePatterns option
  3. Since you are adding a d.ts file in your source that is not managed by tsc, you need to add a script that will perform the following actions:
    1. Copy txt.d.ts in the target directory of the compiled files for your package
    2. Add this line at the top of your package's file loader (e.g. loader/index.d.ts: /// <reference types="../txt" />\r\n - this will link the declaration file back into your package. Note that you can add this reference to any file of your package.

This workaround will only work once you import the file referencing back to the declaration - this is the only way TypeScript can be made aware that this type exists (see https://github.com/microsoft/TypeScript/issues/49124).

Another alternative could also be to add manual steps (in a readme file) to add a global type declaration file.

5 Comments

Could you possible use an NPM postinstall script that makes the file for you? 👀
Yes, I have looked a bit into this and this would be a script that needs to be run manually correct?
I believe that it is run automatically after installing the package.
Thanks for helping me with another question - I was just reading docs.npmjs.com/cli/v8/using-npm/scripts and I think you are right. I will give it a shot tomorrow or over the weekend
I finally had time to check again @catgirlkelly and unless I missed something, postinstall works on the package installing other packages and not the other way around (most likely for security reasons). So unless I missed something there is not really any way to automate this
1

This might not directly help OP but this is how I get globals from parent to child module.

  1. build your js files with declarations
  2. you should have index.js and index.d.ts in you build folder
  3. add your global.d.ts to your build folder
  4. add "import './global'" to index.d.ts

Comments

1

Not much related to your question but I got here because I were looking for global type declaration in nodejs TypeScript.

Put these lines in 'src/types/global.d.ts'

declare global {
    type MyType = {
        messageNumber: number
        message: string | null
    }
}

export {}

and put this in tsconfig.json

"compilerOptions": {
    "typeRoots": ["./src/types"]
}

Now you can access MyType anywhere like this:

const a:MyType

1 Comment

You have to add ""../../node_modules/@types" or the path to your node_modules types folder, otherwise your npm types won't be available

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.