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
}   
10
  • Could you edit the above code to constitute a minimal reproducible example 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 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! Commented Nov 14, 2019 at 15:22
  • Like this maybe? But I don't know what useStyles actually does so I don't know if that signature will fit. Commented Nov 14, 2019 at 15:25
  • Does this answer your question? Interface type check with Typescript Commented Nov 14, 2019 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 Commented Nov 14, 2019 at 15: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 Commented Nov 14, 2019 at 17:02

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

Comments

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.