Creating a new package and a custom theme with TypeScript

I’m encountering some problems when starting a new Frontity project with TypeScript. I’ll list them here to discuss how to approach them:

  • The package.json in the project’s root needs typescript declared as a dev dependency. This should be done in frontity create -t.
  • When you run frontity create-package -t, it is not yet implemented the support for this option (and is not explained in the help command, which leads the developer to believe that there is a bug).
  • The @types/react package is not installed after frontity create and I need to declare it as a dependency somewhere. I think this should be avoidable. We could declare @types/react as a dependency instead of a dev dependency in @frontity/core or maybe, so only people that uses the -t option will download the @types packages, we could declare these packages as dev dependencies in the project’s root, like typescript, when we run frontity create -t (I don’t like this second way, though).
  • I’m not sure if there needs to be a tsconfig.json file in the project’s root. So far it didn’t seem necessary though.
    EDIT: I was doing fine until I used Object.values() which needs the target set to es2017, and only setting that will override all settings so I had to copy all the settings used in the frontity repo.
  • There is a @types/react-helmet dependency here that seems unnecessary, as react-helmet-async is being used.
  • When you add a new field to the package export object, like { state: { theme: { some: "field" } } }, if there isn’t at least one field at the same deep defined in the types, TypeScript won’t complain for declaring a field not typed. I think this is a bug.

PS: I can work on this things once we decide how to fix them.

I’ve been playing a bit and I’d like to know what do you think about this pattern, if it’s a good option or if it presents any problem that I might be missing:

// types.ts

import React from "react";
import { Package, Connect as BaseConnect } from "frontity/types";
import Source from "@frontity/source";
import Router from "@frontity/router";

interface Nispero extends Package {
  name: "nispero-theme";
  roots: {
    theme: React.FC;
  };
  state: {
    theme: {};
  };
  actions: {
    theme: {};
  };
}

export default Nispero;

type Packages = Source & Router & Nispero;
type Connect<Props extends object = {}> = BaseConnect<Packages, Props>;

export { Connect };
// src/root.tsx

import React from "react";
import { connect } from "frontity";
import { Connect } from "../types";

const Root: React.FC<Connect<{ someProp: string }>> = props => (
  <div>
    <p>{props.someProp}</p>
    <p>{props.state.frontity.title}</p>
    <pre>{props.state.theme}</pre>
  </div>
);

export default connect(Root);
type Packages = Source & Router & Nispero;

In my opinion, I’d be more picky about the things your package needs from Source or Router, instead of including everything by default.

type Connect<Props extends object = {}> = BaseConnect<Packages, Props>;

Re-exporting the Connect, already hooked to your package seems fine to me :slight_smile:

I’ve openend a low priority bug for that: https://github.com/frontity/frontity/issues/240

@luisherranz the Analytics example is broken I get TS2749: ‘Analytics’ refers to a value but is being used as type.

while adding to the theme types.ts

analytics?: Analytics["actions"];

Could you advise?

Just a quick suggestion, I think you might want to try analytics?: Analytics['actions']['analytics'], as each package in Frontity might have more than one namespace, this needs to be added after the ['actions'] bit.

@f.napoleoni: did you solve it with @orballo’s suggestion?

By the way, welcome to the community! :grinning_face_with_smiling_eyes: