1

I have an issue in Typescript, where I'm trying to understand how to declare src={close} inside ItemProps{}. I get the following error:

Type '() => void' is not assignable to type 'string'.

Unfortunately, I have no idea how to fix this error.

import * as React from 'react';
import close from '../../assets/close.svg';

export type ItemProps = { 
    /**
     * Close icon source
     */
    src: any;
}

The error occurs in the src={close}

<img className={styles.close} src={close} alt=''/> //src={close} is 'close.svg'

Any help is appreciated! Thank you.

RCohen
  • 1,702
  • 10
  • 24
  • 44
  • 3
    Where do you define `close`? Obviously it is not a string, but a function. – Murat Karagöz Dec 11 '18 at 13:45
  • What do you mean? It's supposed to be an icon for a `` – RCohen Dec 11 '18 at 13:47
  • The stacktrace indicates something else, hence why I am asking. – Murat Karagöz Dec 11 '18 at 13:48
  • This is a way in React JS to use an image/icon – RCohen Dec 11 '18 at 13:50
  • 1
    Can you provide a snippet with the `close` declaration please? Is it imported with webpack's magic like `import close from '../close.svg';`? – SkyzohKey Dec 11 '18 at 13:56
  • Check the question now ;). Actually, this import is not correct @SkyzohKey – RCohen Dec 11 '18 at 14:00
  • 1
    What is `../../assets/close`? A React Component? An SVG file? Something else? – SkyzohKey Dec 11 '18 at 14:01
  • I'm sorry, my mistake. It's an SVG file. @SkyzohKey – RCohen Dec 11 '18 at 14:09
  • Are you sure you have the right loader in your webpack config? A potential solution might be to convert your SVG to a React Component. Benefit here is that you get React flexibility into an SVG. Con is that if your SVG is huge, it might take a bit of time to adapt it. I can create an answer with the SVG to React Component example ;) – SkyzohKey Dec 11 '18 at 14:16
  • Well, I'm not sure if it's the best solution, but why not? :) I appreciate the help! @SkyzohKey – RCohen Dec 11 '18 at 14:18
  • Possible duplicate of [How to display svg icons(.svg files) in UI using React Component?](https://stackoverflow.com/questions/42296499/how-to-display-svg-icons-svg-files-in-ui-using-react-component) – Heretic Monkey Dec 11 '18 at 20:36

4 Answers4

3

() => void indicates that close is of type function that returns void, but the src attributes expects a value of type string. Make sure close is actually a string, or a function that returns a string.

edit: I don't know a lot about react, but apparently loading an svg image isn't that easy, you could have a look a this article

mika
  • 343
  • 1
  • 14
1
<img className={styles.close} src={require('../../assets/close.svg')} alt=''/>

Should do the job! Import will attempt to import as a function. Using require allows you to specify file paths.

  • Seems a nice solution, but I get the following error: `Cannot find name 'require'. Do you need to install type definitions for node?` I already tried this `const close = require('../../assets/close.svg')` after the react import @Spencer Robertson – RCohen Dec 11 '18 at 14:21
1

If it actually is a string in runtime, and you just want TypeScript to stop yelling at you, you just need to fix your typings:

declare module '*.svg' {
  const value: string;
  export default value;
}

This will tell TypeScript that every imported *.svg file exports a string. The above declaration should bet put in a declaration file (example: stubs.d.ts) somewhere in your project.

Karol Majewski
  • 23,596
  • 8
  • 44
  • 53
0

Ok so as the OP asked, here's how one can convert any SVG file to a React Component. This gives you much more control over the SVG and even gives you the power to animate it (i.e. react-popmotion, react-animated, etc) or to update path depending on state. Another cool benefit is that this way you don't need any webpack/gulp/grunt/anything plugin to inline SVGs as they are inlined by React itself ;).

First, open your SVG file, copy the code. Then, create a new file into components/icons/CheckboxIcon.js or similar.

Here's an example of a CheckBoxIcon I made for a project at work:

import React from 'react'
import PropTypes from 'prop-types'

const CheckBoxIcon = props => (
  <svg
    style={{ width: 24, height: 24 }}
    viewBox={'0 0 24 24'}
    onClick={props.onClick}
  >
    <path
      fill={props.checked ? '#1E82E4' : 'rgba(0,0,0,.67)'}
      d={
        props.checked
          ? 'M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Zs'
          : 'M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z'
      }
    />
  </svg>
)

CheckBoxIcon.propTypes = {
  checked: PropTypes.bool,
  onClick: PropTypes.func
}

CheckBoxIcon.defaultProps = {
  checked: false,
  onClick: () => null
}

export default CheckBoxIcon

Then just import it as a regular React component, i.e.:

import CheckBoxIcon from '../icons/CheckBoxIcon';

render () {
  return (
    <div>
      {/* My components... */}
      <CheckBoxIcon />
      <CheckBoxIcon checked={true} />
    </div>
  )
}

For more informations, feel free to check this article on dev.to: https://dev.to/nishanbajracharya/using-svg-icons-components-in-react-163k

SkyzohKey
  • 755
  • 7
  • 16