Typescript image import
Asked Answered
K

5

94

I found a solution here: Webpack & Typescript image import

But I am getting error for this:

[ts]
Types of property 'src' are incompatible.
  Type 'typeof import("*.png")' is not assignable to type 'string | undefined'.
    Type 'typeof import("*.png")' is not assignable to type 'string'.

I guess I need to cast import somehow, but can't figure out how. I am doing this in React. I saw that src attribute is defined as string | undefined, that is why error is popping.

Here is code:

import * as Logo from 'assets/images/logo.png';

HTML:

<img src={Logo} alt="" />

And definition based on above mentioned solution:

declare module "*.png" {
  const value: string;
  export default value;
}

Tsconfig:

{
  "compilerOptions": {
    "baseUrl": "./",
    "jsx": "react",
    "lib": ["es5", "es6", "dom"],
    "module": "commonjs",
    "noImplicitAny": false,
    "outDir": "./dist/",
    "sourceMap": true,
    "strictNullChecks": true,
    "target": "es5",
    "typeRoots": [
      "custom_typings"
    ]
  },
  "include": ["./src/**/*.tsx"],
  "exclude": ["dist", "build", "node_modules"]
}
Klan answered 29/6, 2018 at 11:9 Comment(5)
According to here you should use require instead of import. So it should look like this: const Logo = require('assets/images/logo.png')Giagiacamo
Yep i saw that. But that is not elegant way of doing this. The thing is that when you do import it works when you load app. But you get lint error.Klan
import works so it should be used. @MarioPetrovic a default import has no name. That is why you can leave out the * as part. import Logo from './logo.jpg' is fine because it's equivalent to const Logo = require(./logo.jpg)Killie
<img src={require('assets/images/logo.png')} /> works. What makes it not elegant, if you only need to reference it in that one line? To me, it feels more elegant and bulletproof than modifying d.ts files.Exothermic
Well it is probably more of a judgement call. But if you setup it with d.ts and use it later in your project it makes it more organic and consistent with regular importing.Klan
R
180

One of the ways to get rid of that error is by modifying d.ts file as follows:

declare module "*.png"

remove

{
  const value: string;
  export default value;
}

or alternatively you can do:

declare module "*.png" {
  const value: any;
  export default value;
}

Update

The best solution with type-checking is:

declare module "*.png" {
   const value: any;
   export = value;
}
Revocation answered 3/7, 2018 at 22:4 Comment(15)
Already tried to modify from string to any and it wont help. It seems that const value is not getting considered when resolving type of imported. As for removing block, it wont work either.Klan
You can also try this: declare module '*.png' { const value: string; export = value; }Revocation
Hey. Just tried it with export = value and it worked. It also gives string as type for imported Logo. Also, sorry, but your solution to exclude block of code actually worked, so only declare module "*.png" worked but didn't give type. So please modify your answer to include solution with export = value as best option because of type checking. Thanks very much.Klan
I want to import svg, png, jpg, jpeg, ... so I have to copy paste declare module or could we define something like regular expressionWiredraw
I get: TS1192: Module '"*.png"' has no default export.Diffraction
@Diffraction you were probably not doing it on d.ts / custom.d.ts, but somewhere else...Marigraph
I added the last solution to my custom.d.ts, and it fixed my tslint error, thank you!Erving
downvoted this answer. This does not work Parsing error: Only declares and type imports are allowed inside declare module. I tried declare module "*.png" { const value: any; export = value; } and also tried declare module '*.png' { const value: string; export = value; } and it's complaining about constIsmaelisman
I had trouble getting this to work due to this long-standing issue. As soon as I moved my wildcard declare module statements into their own typings file, rather than an existing globals.d.ts I had for other stuff (which happened to import an interface declaration...), I was able to import LOGO from "./logo.png".Evvoia
The .d.ts file needs to be put into the src/ folder to be working, in case anybody else encounters that problem putting it in the project root.Scummy
I'm annoyed to say my issue is just with IntelliJ IDE just underlining the import. It compiles just fine and even using // @ts-ignore suppresses the red underline error. I've tried everything to gain the smart resolution for my IDE; changing syntax was really a last resort const logo = require("*.png"); which was successful in both compilation and now on my editor.Pokeberry
I get the following error when declaring image imports as a string: 'string' only refers to a type, but is being used as a value here.ts(2693)Cultus
For me the only solution is to ignore the error with // @ts-ignore. I can't fathom why such a basic function as loading an image is not working in parcel ?Cultus
@PiyushZalani in your answer, can you describe why the "best solution" in the Update section is better than the original solution?Somewhat
Saying that you get type checking with setting something to any is just wrong. any overrides ALL type checking for that value. It should be avoided whenever possible.Slaw
J
41

For react-native

create global.d.ts file on project root folder and just add next lines there

declare module '*.png' {
  const value: import('react-native').ImageSourcePropType;
  export default value;
}
Jeans answered 12/11, 2021 at 14:31 Comment(4)
That's a nice solution, you can also change the value type as your need.Asphaltite
This works well, but I wish TypeScript checked that files exist when importing them. As-is, it allows me to import a non-existent file, which would result in a runtime error. I've been searching for a way to preserve file existence checks like we get from importing JS/TS but haven't found a way yet.Phelps
for react-native I've just created a types.d.ts in the root with the simplest answer and worked like a charm: `declare module "*.png"Sales
@FacundoColombier sure. It is just the same, but with type. And what type did you get in code? It will solve problem with file absence? :)Jeans
S
5

I created the index.d.ts and added 'declare module "*.jpg"' it didn't work but when I changed the name to custom.d.ts (or any other name) it worked fine.

Spiritualty answered 28/9, 2022 at 17:22 Comment(0)
M
2

In my case, even with the global.d.ts configured, it wasn't working due to the import. instead of

import * as Logo from 'assets/images/logo.png';

i used:

import image from 'assets/images/logo.png';

it worked fine.

Memorable answered 5/4, 2023 at 12:38 Comment(0)
J
0

You first need to create a new TypeScript declaration file with the file extension .d.ts. For my project I named it custom.d.ts and put it in my src directory. Then add the code suggested in the accepted answer to that file:

declare module "*.png" {
   const value: any;
   export = value;
}
Jacey answered 11/4 at 3:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.