yandex / reshadow

Markup and styles that feel right
https://reshadow.dev
Other
363 stars 15 forks source link

How to use reshadow with TypeScript? #40

Open comerc opened 5 years ago

comerc commented 5 years ago

Property 'container' does not exist on type 'JSX.IntrinsicElements'. TS2339

import React from 'react'
import styled, { css } from 'reshadow/macro'

const styles = css`
  container {
    border: 1px solid red;
  }
`

class ReshadowPage extends React.Component<any> {
  render() {
    return styled(styles)`
      container {
        border: 1px solid green;
      }
    `(<container>Dummy</container>)
  }
}

export default ReshadowPage
comerc commented 5 years ago

I do NOT like this solution.

./react-app-env.d.ts

/// <reference types="react-scripts" />

declare namespace JSX {
  interface IntrinsicElements {
    [name: string]: any
  }
}
antonk52 commented 5 years ago

Thank you for the issue. And it is indeed a good one.

This is a good question since I use reshadow daily. But yet to use it in a typescript project.

Off top of my head I can only think of having a list of acceptable component names which will have the same interface a regular div component i.e. same attributes, handlers and so on. This may also be beneficial since you can make sure no one on your team will have typos in component names. This is something which reshadow makes easily forgiven. Another advantage of this approach can be that every one will have a clear list of additional names they can call components instead of winging it as they go. Last one can be controversial but I think it's a good start.

I'm going to have a think about this topic. Perhaps there can be a better solution for this problem. If you have any suggestions please do share!

lttb commented 5 years ago

Hi @comerc, thank you for the issue!

In addition to the things that @antonk52 mentioned, I want to note, that there is also possible to use custom elements this way:

<use:container>Dummy</use:container>

And if you don't want to use namespaces:

import styled, {use} from 'reshadow'

styled`
  ...
`
(<use.container>Dummy</use.container>)

I'm not sure that it will work with typescript well because we don't use typescript in our project (we use flow instead), but it looks like it should work.

And this is an undocumented feature, because there are still some things that we need to think about (like, consistent way for declaring elements, should we support the one way described above, or both and so on), but I would be glad if you will give it a try and come back with some feedback 🙂

BTW, we're going to add type declarations for the flow and typescript soon.

comerc commented 5 years ago

1) <use:container> does not work in TypeScript: Parsing error: Identifier expected

2) How to use use from reshadow?

import styled, {use} from 'reshadow'
...
  render() {
    const { b } = this.state
    const color = b ? 'red' : 'green'
    const width = b ? 1 : 2
    // FIXED: calc() as workaround for dynamic px variable
    // https://github.com/lttb/reshadow/issues/23
    return styled(styles)`
      container {
        border: calc(${width} * 1px) solid ${color};
      }
    `(<use.container onClick={this.handleClick}>Dummy</use.container>)
  }
...

Снимок экрана от 2019-06-23 21-07-33

I see insertion to inline style from variables without border.

antonk52 commented 5 years ago

@comerc from your screenshot I can see that the html element it not getting the class name. Do you have this project on github or codesandbox? I would like to take a closer look. If not than can you make a gist of your config files in order to reproduce the problem?

comerc commented 5 years ago

@antonk52

Edit reshadow-cra-wudfn

gus3inov commented 5 years ago

Hi, i'm using typescript 3.2.2 and getting an error when using use namespace. (JSX attribute) use: true Identifier expected.ts(1003)

<button use:size={size} use:bg={bg}>
    {props.children}
</button>
lttb commented 5 years ago

hi @gus3inov, at this moment it would be better to use the use function, because it looks like TS parser does not support namespaces

import {use} from 'reshadow'

<button {...use({size, bg})}>
    {props.children}
</button>
gus3inov commented 5 years ago

Thanks for feedback @lttb ! use function worked for me, but i'm think it's bad for typings component. What if I add pull request with types like these ?

const _Symbol = (key: string) => (typeof Symbol !== 'undefined' ? Symbol(key) : key);

const use = <T>(obj: T) => {
    const result: {use: T} = {
        use: obj
    };
    return result;
};
lttb commented 5 years ago
const _Symbol = (key: string) => (typeof Symbol !== 'undefined' ? Symbol(key) : key);

const use = <T>(obj: T) => {
    const result: {use: T} = {
        use: obj
    };
    return result;
};

I'm not sure, that this is correct, because in fact the type of use function is something like

declare function use<T: {[string]: string | number | boolean}>(T): {||}

because the result will be omitted in the runtime and will not affect the component/element interface

gus3inov commented 5 years ago

Yes, you are right, generic constraint looks good.

lttb commented 5 years ago

@comerc @gus3inov we've just released the 0.0.1-alpha.69 version with basic typescript and flowtype support, there is an example of next + reshadow + typescript: https://codesandbox.io/s/reshadow-next-typescript-yok5b

hope to add some docs with examples and explanation soon

comerc commented 5 years ago

I see "Container Error"

Снимок экрана от 2019-09-30 21-54-29

artalar commented 4 years ago

Another issue is undeclared styled.styles: image