6

I'm currently working on a React project using TypeScript and I come across a very stupid problem and on top of that very annoying...

For example I create a dummy component called Page that need a page of type Page as props:

interface Props {
  page: Page
}

export interface Page {
  id: number
  category: PageCategory
  path: string
  name: string
}

const Page: React.FunctionComponent<Props> = (props) => {
  ...
  return (
    ...
    <h1>{ props.page.name }<h1/>
    ...


export default Page

So far no problem but they're coming as soon as I decide to import the component with the type:

import Page, { Page } from './component/Page'  // ts-error: 'Duplicate identifier 'Page''

So in order to avoid this problem I added the prefix I to all my interfaces like IPage but I'm sure there's a more elegant way to do it. How do you handle that?

johannchopin
  • 13,720
  • 10
  • 55
  • 101
  • 1
    You can name default export whatever you like when you import it... But real solution is to give different names for different things. – Aleksey L. Mar 20 '20 at 12:25
  • 1
    There are already [issues](https://www.typescriptlang.org/play/?jsx=2&ssl=1&ssc=1&pln=17&pc=20#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wFgAoC4AOxiSk3STgAUcwBnOAbwrjjAoA5kgBcrYUgoBfChSQAPSLDg06DJhJE8+qgCbjqAVxAAjerrQo6Q6AE9xHGFBpDdgmAAtHz17uooIGJwTi7UbuSylORoENROWsHI6DAAdABiRtQYwHEAwriQ1Ei0ADxsEJwAfHAAvHAAFGDsHACUdVW6pZ4AjFXczZUcqYIiqQFB0nClAPS9ndGKyvB6SIxGADbwLJJAA) without an import: exported `Page` gets `any` type – ford04 Mar 20 '20 at 12:28
  • @AlekseyL. `But real solution is to give different names for different things` yeah sure but what would be an other name for the type `Page`? Because the object is like a `Page` – johannchopin Mar 20 '20 at 12:54
  • @ford04 I don't really get it what's the issues in the example? – johannchopin Mar 20 '20 at 13:36
  • @johannchopin it's not clear what you are exporting, interface `Page` and `const Page` clash together. As Aleksey says, just give them different names. – ford04 Mar 20 '20 at 14:20
  • @ford04 Yea sure it will solved the problem and I will loved too. But the fact is that what would be an other name for the interface that **make sense**? Because as said before the interface is a `Page` and it would be overkill to call it `PageData` or something like this :/ Do you understand the issue here? :) – johannchopin Mar 20 '20 at 14:26

3 Answers3

6

Your solution is close. Just use the same export "style" for both objects, so that you can import them together. Page will be an alias for both the Value and the Type.

./component/Page.ts

interface Page { ... }
const Page: ...

export default Page

./App.ts

import Page from './component/Page'

const pageData: Page = { id: ... }
const pageComponent = Page 

Tiberiu Maran
  • 1,983
  • 16
  • 23
  • 1
    This is really a good question.I also encountered it before, and I choose a workaround that is giving it another name. But I still can't let it go. Thanks @johannchopin 's insist, finally I also see this acceptable answer. However, one question is using declaration merge means I can't separate declaration with component, it must be in same module, right?It againsts best practice putting all declarations in one place. Any comments for this, guys? – June Wenston Feb 19 '21 at 07:39
0

The main problem is because you have same name for your interface and component and you're both exporting it.

The easiest solution would be to rename your interface/type. Just add the word Props to it for it to still make sense (or any postfix you like)

interface Props {
  page: PageProps
}

export interface PageProps {
  id: number
  category: PageCategory
  path: string
  name: string
}

const Page: React.FunctionComponent<Props> = (props) => {
  ...
  return (
    ...
    <h1>{ props.page.name }<h1/>
    ...


export default Page

So wont have problem in importing it like this

import Page, { PageProps } from './component/Page'
JkAlombro
  • 1,696
  • 1
  • 16
  • 30
  • Yes I know it: `So in order to avoid this problem I added the prefix I to all my interfaces like IPage`. But is not encouraged and moreover It's make here no sense. The interface is not a `Props`. It's an object that contains all data from a `Page`. But calling him `PageObject` makes as much sense as calling it `IPage` and it's not a good practice. – johannchopin Mar 23 '20 at 10:11
  • @johannchopin yeah `PageObject` is indeed good and better than `PageProps`. As long as you change the name of the interface (which is what my answer suggests), your problem will be solved. – JkAlombro Mar 23 '20 at 10:15
  • Have you read the end of my comment? It is not a good practice to add a postfix like that it's like using the `I` prefix which is greatly discouraged. – johannchopin Mar 23 '20 at 10:30
  • 1
    @johannchopin if that's the case, why not name your component as "PageComponent" instead? And if you also consider that as a "bad practice", why not create a single file dedicated for interfaces so that you wont have to export it alongside your component which has the same name? – JkAlombro Mar 24 '20 at 02:18
  • Yeah I think also that would more sense to rename the react component. But the postfix `Component` is also not really a good practice. I already implemented the 'one file for all interfaces' concept but yeah it's very dirty to do it. I posted a question on this topic https://stackoverflow.com/questions/60740173/handle-self-written-types-definition-in-typescript-project – johannchopin Mar 24 '20 at 09:16
0

you can do it using a namespace, but it will add a layer of complexity.

Create Types.ts file

export namespace Types {
    export interface Page {
         id: number
         category: PageCategory
         path: string
         name: string
     }
}

and use it with Types.Page.

for example

const getName = (page: Types.Page) : string = page.name
samasoulé
  • 193
  • 2
  • 3
  • 11
  • Interesting solution thanks. However when you need to import multiple components you also probably need to import multiple namespaces with the same name `Types`. So you will end up making them unique like `PageTypes.Page` which is worse than just `PageType` IMO. – johannchopin Jun 10 '22 at 08:07