garronej / tss-react

✨ Dynamic CSS-in-TS solution, based on Emotion
https://tss-react.dev
MIT License
608 stars 37 forks source link

Property ''@font-face'' is incompatible with index signature. #50

Closed paales closed 2 years ago

paales commented 2 years ago
Schermafbeelding 2022-01-05 om 11 48 39

I'm using the material ui createStyles and try to inject the complete styles of body1.

const useStyles = makeStyles()((theme) => ({
  root: {
    ...theme.typography.body1,
  },
}))

This will however give an error:

Argument of type '(theme: Theme) => { root: { backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: AccentColor | undefined; ... 783 more ...; vectorEffect?: VectorEffect | undefined; }; }' is not assignable to parameter of type 'Record<"root", CSSObject> | ((theme: Theme, params: void, classes: Record<never, string>) => Record<"root", CSSObject>)'.
  Type '(theme: Theme) => { root: { backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: AccentColor | undefined; ... 783 more ...; vectorEffect?: VectorEffect | undefined; }; }' is not assignable to type '(theme: Theme, params: void, classes: Record<never, string>) => Record<"root", CSSObject>'.
    Call signature return types '{ root: { backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: AccentColor | undefined; alignContent?: AlignContent | undefined; ... 782 more ...; vectorEffect?: VectorEffect | undefined; }; }' and 'Record<"root", CSSObject>' are incompatible.
      The types of 'root' are incompatible between these types.
        Type '{ backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: Property.AccentColor | undefined; alignContent?: Property.AlignContent | undefined; ... 782 more ...; vectorEffect?: Property.VectorEffect | undefined; }' is not assignable to type 'CSSObject'.
          Property ''@font-face'' is incompatible with index signature.
            Type 'Fontface | Fontface[]' is not assignable to type 'CSSInterpolation'.
              Type 'Fontface' is not assignable to type 'CSSInterpolation'.
                Type 'Fontface' is not assignable to type 'CSSObject'.
                  Index signature for type 'string' is missing in type 'FontFace<0 | (string & {}), string & {}> & { fallbacks?: FontFace<0 | (string & {}), string & {}>[] | undefined; }'.ts(2345)

I've ran into this issue in another situation in the past and in that case it was a version mismatch with csstype, but I've tripple checked but this doesn't seem to be the case.

It is because of this line in Material UI, if I temporarily comment this out, it wont throw the error: https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/styles/createTypography.d.ts#L38

paales commented 2 years ago

Oh there are more issues after I've commented out the @font-face:

(property) body2: CSSProperties
Argument of type '(theme: Theme) => { review: { accentColor?: AccentColor | undefined; alignContent?: AlignContent | undefined; alignItems?: AlignItems | undefined; ... 782 more ...; vectorEffect?: VectorEffect | undefined; }; ... 10 more ...; container: { ...; }; }' is not assignable to parameter of type 'Record<"review" | "title" | "meta" | "nickname" | "date" | "reviewsBottomContainer" | "paginationRoot" | "paginationButton" | "ratingRow" | "rating" | "writeReviewButton" | "container", CSSObject> | ((theme: Theme, params: void, classes: Record<...>) => Record<...>)'.
  Type '(theme: Theme) => { review: { accentColor?: AccentColor | undefined; alignContent?: AlignContent | undefined; alignItems?: AlignItems | undefined; ... 782 more ...; vectorEffect?: VectorEffect | undefined; }; ... 10 more ...; container: { ...; }; }' is not assignable to type '(theme: Theme, params: void, classes: Record<never, string>) => Record<"review" | "title" | "meta" | "nickname" | "date" | "reviewsBottomContainer" | "paginationRoot" | ... 4 more ... | "container", CSSObject>'.
    Call signature return types '{ review: { accentColor?: AccentColor | undefined; alignContent?: AlignContent | undefined; alignItems?: AlignItems | undefined; alignSelf?: AlignSelf | undefined; ... 781 more ...; vectorEffect?: VectorEffect | undefined; }; ... 10 more ...; container: { ...; }; }' and 'Record<"review" | "title" | "meta" | "nickname" | "date" | "reviewsBottomContainer" | "paginationRoot" | "paginationButton" | "ratingRow" | "rating" | "writeReviewButton" | "container", CSSObject>' are incompatible.
      The types of 'nickname' are incompatible between these types.
        Type '{ [x: string]: unknown; accentColor?: Property.AccentColor | undefined; alignContent?: Property.AlignContent | undefined; alignItems?: Property.AlignItems | undefined; ... 782 more ...; vectorEffect?: Property.VectorEffect | undefined; }' is not assignable to type 'CSSObject'.
          'string' index signatures are incompatible.
            Type 'unknown' is not assignable to type 'CSSInterpolation'.
              Type 'unknown' is not assignable to type 'ArrayCSSInterpolation'.ts(2345)
garronej commented 2 years ago

Hi @paales,
Just for a bit of context this would be an issue for csstype.
It's an implicit peer dependency of tss-react, @emotion/react depends on it.

That said { [x: string]: unknown; } is not a valid CSSObject, a compile time error is expected.

The problem is that, it might work at runtime in most of the cases but, type-wise, typeof theme["typography"]["body1"] is not a valid CSSObject. There is nothing I can do about it except maybe offering a muiTypographyToCssObject(theme.typography.xxx) utility...

paales commented 2 years ago

Thanks for your feedback.

The TS error goes away if we change the following: https://github.com/garronej/tss-react/blob/v3.3.0/src/tools/types/CSSObject.ts#L63-L65

To:

export interface CSSOthersObject {
  [propertiesName: string]: unknown | CSSInterpolation
}

I can't really judge what the ramifications of this are, but it does make the typescript error go away 🤓

paales commented 2 years ago

Which happens here as well by the way: https://github.com/mui-org/material-ui/blob/259952855e31dfde8c9daa3d7d00f6d88e35f27b/packages/mui-styled-engine/src/index.d.ts#L27-L29

garronej commented 2 years ago

Hi @paales,
Thank you for investigating. I won't, however, add | unknown it would result in drastically reducing the type safety that TSS provides.
My hands are tied here, there is nothing I can do from where I stand.
I suggest that you cast as CSSObject, as any or you submit an issue @mui-org.

Best

paales commented 2 years ago

Well that makes sense, going to find another solution. Thanks a lot for your time!

garronej commented 2 years ago

Ok, let me know what you end up doing, in my opinion, in this particular instance, there is no problem in casting as any or as CSSObject.

paales commented 2 years ago

Created a minimal helper function to solve the issue:

export function typography(theme: Theme, key: keyof Theme['typography']): CSSObject {
  return theme.typography[key] as CSSObject
}

Using it like this:

const useStyles = makeStyles()((theme) => ({
  root: {
    ...typography(theme, 'body1')
  },
}))
paales commented 2 years ago

FYI: I've migrated our Material UI project with the help of tss-react in about 15 hours. I'm very happy with this! Thanks a lot!

garronej commented 2 years ago

FYI: I've migrated our Material UI project with the help of tss-react in about 15 hours. I'm very happy with this! Thanks a lot!

Nice, what is the website?