2

I'm currently translating my style solution based on jss to typescript and I've stumble in the following situation.

Consider my basic setup

import { useStyles } from './styles'

const styles = theme =>({
    root : { color: 'white' },
    foo : { backgroundColor: 'red' },
})

const Component = () =>{
    const classes = useStyles(styles)

    return <div className={classes.root} />
}

You pass a style's object to useStyles and the returned value is an object which contains all keys declared inside styles. So my classes object looks like this

{
    root : 'random-name123',
    foo : 'random-name124'
}

Since I can't possibly know which keys styles will have, my current interface for classes is just a dictionary

interface Classes {
    [index: string]: string
}

My question is:

Can I declare an interface in such a way that all keys passed to styles are declared as being part of Classes? So that when I type classes. I would be able to see all possible keys for classes?

In other words, I want the keys which compose Classes to be predictable. So that if I pass a styles objects like this

{
    foo : {/*...*/},
    bar: {/*...*/}
}

My Classes interface would look like

{
    foo : string,
    bar : string
}   
Dupocas
  • 20,285
  • 6
  • 38
  • 56
  • Could you edit the above code to constitute a [mcve] so that someone can drop it into an IDE and give you an answer they can test first? Right now my *guess* is that you want `useStyles` to be a [generic](https://www.typescriptlang.org/docs/handbook/generics.html) function whose output type is dependent on its input type. But without usable example code I don't know if that is what you really want. Good luck! – jcalz Nov 14 '19 at 15:22
  • Like [this](http://www.typescriptlang.org/play/#code/CYUwxgNghgTiAEAzArgOzAFwJYHtX2QGcQBlDATwhEIB4AVAPgAoAPALnlY6lXIEp4AXgbw6fDgG94AbQDS8LPgDWIcjkSiAuh0IYYigObwAvgG4AUObB5d8XZWpDOGABYgAtiG68BwzhPN4IPgYHBwMSXhrCBwYDgByAHcXLAwQeJMAGkDgxDDIgCMoMCUDULRgAGEcGLj4eLhgDONs4z5La1RbavcABzwQVAwnJl8RAOCom2HIKEJiQiciUgoqQiZ7Nb4LSdn56gA6PJxTeAB6M7s9QxygvYWD0PDTi6v9VANbqOh9wgPksK9QgvS4gGChGCZeAAIgBOCB0PgqHC8AAblAIFhgPAVORzMYgA) maybe? But I don't know what `useStyles` actually does so I don't know if that signature will fit. – jcalz Nov 14 '19 at 15:25
  • Does this answer your question? [Interface type check with Typescript](https://stackoverflow.com/questions/14425568/interface-type-check-with-typescript) – Jurrian Nov 14 '19 at 15:33
  • @jcalz Problem is that I have a LOT of boilerplate code to reproduce in sandbox. I've updated the question. That helps? Case isn't enought I'll try to reproduce it in a sandbox – Dupocas Nov 14 '19 at 15:45
  • I'd assume you could make a toy version of `useStyles()` that demonstrates your issue without having to migrate a lot of boilerplate code. I mean, it could be [this](http://www.typescriptlang.org/play/#code/JYOwLgpgTgZghgYwgAgCoAsIFsUG8BQyRyA7ugPYDSI5JAzgFzJ1hSgDmA3PgL74LkQLZuRwZsEJuJzIAvMlykK1Wo2QAiCiQAmAT3XIe3GAFcQCMMEHITdCAGUwugDYQ6ACgQAjJu4AeUpg4AJRyAHzIcCC6oQTEyAJCYMgAbnDOcgle7nSiENIQwdzxicJQEGBMigDaANZMLGwg7AC6Dawchpm4RoTEAPJeAFYQFgB0tRC6HmnOwWMw5FAAoojo7rXhyOVgdS2ZAFL2-QByY40cwDC67rN7wUV9RDsmUCDbFdx8peSuY87kdjuWwOJyuDzuUKyCLuRRwKrIHwadBYLAGHiGB7BfBAA) for all I know. – jcalz Nov 14 '19 at 16:06
  • Check this guy: https://github.com/mrmckeb/typescript-plugin-css-modules – makeitmorehuman Nov 14 '19 at 16:29
  • This is indeed interesting. But I'm not using css. – Dupocas Nov 14 '19 at 16:34
  • I'll reproduce in a sandbox @jcalz – Dupocas Nov 14 '19 at 16:35
  • @Dupocas is my answer valid or I misunderstood? – Abido Nov 14 '19 at 16:45
  • 1
    Both answers helped me. I'm still having some issues but not related to the scope of the question. I'm just waiting a little bit to accept one. Hoping that you can get more upvotes hahah – Dupocas Nov 14 '19 at 17:02

2 Answers2

3

I hope this is what you meant:

const styles = {
  root: 'value1',
  foo: 'value2'
};

type stylesType = typeof styles;

interface Classes extends stylesType {
  [x: string]: string;
}

Now when an object is typed as Classes it will have the keys root and foo.

Inspired by Types from both keys and values of object in Typescript

Abido
  • 752
  • 6
  • 18
1

In Typescript, you can use the Record utility type to map a union of types to another type in a dictionary.

To get all keys of a defined object, you can use keyof typeof object, which would give you "root" | "foo" in your case.

So, if you want to map all keys to strings, use:

type Classes = Record<keyof typeof styles, string>
Danilo Fuchs
  • 911
  • 8
  • 17