theo icon indicating copy to clipboard operation
theo copied to clipboard

Typescript output?

Open StevenLangbroek opened this issue 7 years ago • 14 comments

I see there's no option for outputting typescript, but formats look relatively straightforward to write. Would you be interested in a typescript formatter?

Thanks!

StevenLangbroek avatar Nov 16 '18 14:11 StevenLangbroek

I'd be interested in seeing what that looks like.

trazek avatar Nov 17 '18 00:11 trazek

I'd be interested in seeing what that looks like.

Initially probably not that different from the common.js one. I'm still exploring Theo though, so depending on how it works it might be interesting to output an enum or union per category.

StevenLangbroek avatar Nov 17 '18 09:11 StevenLangbroek

Yeah, I think Typescript could be interesting if we can output a format that is useful for everyone.

aputinski avatar Nov 25 '18 03:11 aputinski

Our design system uses TypeScript and I wanted to leverage autocomplete in VSCode when referencing Theo-generated styles/themes in React components. The quickest solution was to auto-generate typings for the JS module using tsc and its --declaration flag. Example output: https://gist.github.com/petekp/8e706a272b7999e20ea7146b77fd42d8

It only generates the primitive types, e.g. string, number, etc. which has been sufficient for autocompleting theme properties. These annotations could be further refined to specific tokens, but I haven't found this necessary just yet.

petekp avatar Dec 08 '18 01:12 petekp

@petekp that link gave me a 404.

trazek avatar Dec 08 '18 16:12 trazek

@trazek Oops, fixed :)

petekp avatar Dec 08 '18 16:12 petekp

@petekp Could you walk through how you generated the typings for that? tsc --declaration tokens.js doesn't love that it's not a TS file.

mattfelten avatar Mar 27 '19 02:03 mattfelten

@mattfelten I'm currently faking it by registering a custom format (.d.ts) and outputting the style data but wrapped in a typings export declaration; basically gluing together the same output tsc --declaration would emit:

// Convert styles to JS and sort them by category
const categorizeStyles = (styleMap: ImmutableStyleMap) => {
  const styleProps: ThemeStyle[] = styleMap.get('props').toJS()
  return chain(styleProps)
    .sortBy('name')
    .groupBy('category')
    .value()
}

// Convert styles into an easily consumable JS object ("theme")
export const createThemeObjectFromStyles = (
  styleData: ImmutableStyleMap
): Readonly<Theme> => {
  return Object.entries(categorizeStyles(styleData)).reduce(
    (acc, [category, styles]) => ({
      ...acc,
      ...styles.reduce((acc2, style) => {
        return {
          ...acc2,
          [style.name]: style.value,
        }
      }, {}),
    }),
    {}
  )
}

// Create a `.d.ts` file and inject the theme object with typings export declaration
theo.registerFormat(
    'd.ts',
    styleMap =>
      `export declare const _default: 
        ${JSON.stringify(createThemeObjectFromStyles(styleMap))}
      `
  )

petekp avatar May 29 '19 01:05 petekp

Ah that's clever. I ended up registering a new ts format and then running tsc on it.

module.exports = theo => {
	theo.registerFormat(
		"ts",
`
// Source: {{stem meta.file}}
const tokens = {
	{{#each props}}
	{{camelcase name}}: '{{value}}',
	{{/each}}
};
export default tokens;
`
	);
}

mattfelten avatar May 29 '19 02:05 mattfelten

@mattfelten Nice! Before my current method I was using my node build script to change the filename from .js->.ts, run tsc --declarations and then change it back to .js 😄

It would be cool to build TS typing support into Theo, perhaps either as an officially supported format on its own (.d.ts), as an option for a .ts format, or perhaps a CLI flag (--tsDeclarations). The latter might be more amenable for custom JS-based formats.

petekp avatar May 29 '19 22:05 petekp

I'll just chime in and say that I don't have any plans to add TypeScript support, but I'd happily accept a PR for it.

aputinski avatar May 31 '19 17:05 aputinski

I'm down to help implement this. Still wondering what exactly folks would expect from this format. Just definitions? Auto-generated types/interfaces? Thinking optionally outputting .d.ts definitions for the built-in JS format(s) would be a reasonable place to start.

petekp avatar May 31 '19 19:05 petekp

That’s what I would expect. That the output can be packaged and “just work” in typescript projects. I don’t think we would need actual .ts files

mattfelten avatar May 31 '19 22:05 mattfelten

I used the following which output a TS declaration which matches the module.js theo format:

const {
  pipe,
  get,
  map,
  camelCase,
  method,
  sortBy,
  join,
} = require("lodash/fp");

const toConstDeclaration = ({ name, value }) =>
  `export declare const ${camelCase(name)} = ${JSON.stringify(value)}`;

module.exports = pipe(
  method("toJS"),
  get("props"),
  sortBy("name"),
  map(toConstDeclaration),
  join(";\n")
);

You can then register this in your setup file:

const typescriptFormat = require("./formats/typescript")

module.exports = theo => {
	theo.registerFormat("d.ts", typescriptFormat)
}

WickyNilliams avatar Dec 14 '20 15:12 WickyNilliams