prismicio / prismic-react

React components and hooks to fetch and present Prismic content
https://prismic.io/docs/technologies/homepage-reactjs
Apache License 2.0
154 stars 40 forks source link

Proposed TypeScript typings #42 #61

Closed sessa closed 3 years ago

sessa commented 4 years ago

Suggest updated typings for issue #42

I am not completely familiar with the libraries and dependencies but these typings should be a bit clearer and usable.

Currently the project does not build typings into its distribution, so I have copied these typings into my project as such:

declare module 'prismic-reactjs' {
  import React from 'react';

  enum Elements {
    heading1 = 'heading1',
    heading2 = 'heading2',
    heading3 = 'heading3',
    heading4 = 'heading4',
    heading5 = 'heading5',
    heading6 = 'heading6',
    paragraph = 'paragraph',
    preformatted = 'preformatted',
    strong = 'strong',
    em = 'em',
    listItem = 'list-item',
    oListItem = 'o-list-item',
    list = 'group-list-item',
    oList = 'group-o-list-item',
    image = 'image',
    embed = 'embed',
    hyperlink = 'hyperlink',
    label = 'label',
    span = 'span',
  }

  export type HTMLSerializer<T> = (
    type: ElementType,
    element: any,
    text: string | null,
    children: T[],
    index: number
  ) => T;
  export interface RichTextProps {
    Component?: React.ReactNode;
    htmlSerializer?: HTMLSerializer<T>;
    linkResolver?: () => string;
    serializeHyperlink?: () => string;
    render: () => React.DOMElement;
  }

  class RichText extends React.Component<RichTextProps, any> {
    static asText(text: string): string;
  }

  interface Link {
    url(link: any, linkResolver?: (doc: any) => string): string;
  }

  const Link: Link;
  const Date: Date = <string>(): Date => {};

  export { RichText, Elements, Link, Date };
}
ohlr commented 4 years ago

import React, { ElementType } from "react";

image

ohlr commented 4 years ago

Cannot find name 'T'.ts(2304)

Generic type 'DOMElement<P, T>' requires 2 type argument(s).ts(2314)

'string' is declared but its value is never read.ts(6133) Initializers are not allowed in ambient contexts.ts(1039) Type '() => Date' is missing the following properties from type 'Date': toDateString, toTimeString, toLocaleDateString, toLocaleTimeString, and 37 more.ts(2740) types.d.ts(52, 22): Did you mean to call this expression? Type parameter name cannot be 'string'.ts(2368)

noblica commented 4 years ago

@ohlr I'm not getting these errors...it's all green for me. Did you manage to find what the issue was?

hypervillain commented 4 years ago

I also get some issue around Date. I'm curious if it can be related to #33 ?

schwigri commented 4 years ago

How does something like this work to address the issue around Date as well as the issues mentioned by @ohlr above?

declare module "prismic-reactjs" {

    enum Elements {
        heading1 = "heading1",
        heading2 = "heading2",
        heading3 = "heading3",
        heading4 = "heading4",
        heading5 = "heading5",
        heading6 = "heading6",
        paragraph = "paragraph",
        preformatted = "preformatted",
        strong = "strong",
        em = "em",
        listItem = "list-item",
        oListItem = "o-list-item",
        list = "group-list-item",
        oList = "group-o-list-item",
        image = "image",
        embed = "embed",
        hyperlink = "hyperlink",
        label = "label",
        span = "span",
    }

    export type RichTextSpan = {
        start: number;
        end: number;
        type: "strong" | "hyperlink";
        data?: {
            link_type: string;
            url: string;
            target?: string;
        };
    };

    export type RichTextBlock = {
        type: Elements;
        text: string;
        spans: RichTextSpan[];
    };

    export type HTMLSerializer<T> = (
        type: React.ElementType,
        element: any,
        content: string,
        children: T[],
        key: string
    ) => T | null;

    export interface RichTextProps {
        Component?: React.ReactNode;
        elements?: {};
        htmlSerializer?: HTMLSerializer<React.ReactNode>;
        linkResolver?: () => string;
        render?: RichTextBlock[];
        renderAsText?: any;
        serializeHyperlink?: () => React.ReactNode;
    }

    export const RichText: React.FC<RichTextProps> & {
        asText: (input: RichTextBlock[]) => string;
        render: (input: RichTextBlock[]) => React.ReactNode;
        displayName: "RichText";
    };

    interface LinkProps {
        url(link: any, linkResolver?: (doc: any) => string): string;
    }

    export const Link: React.FC<LinkProps> & {
        url: (link: any, linkResolver?: (doc: any) => string) => string;
    };

    interface PrismicDate {
        (date?: string): Date;
    }

    export const Date: PrismicDate;
}

Edit: I also believe the typings file index.d.ts needs to be in the root level of the package and not in the typings folder.

noblica commented 3 years ago

@sessa the render method needs to be static, for it to be called like so: RichText.render(...)

@schwigri I really like your suggestion! Especially because of the RichTextBlock addition. I'm pretty new to using this library, so I'm not sure if I can help much in expanding it further ATM.

ohlr commented 3 years ago

@schwigri works like charm!

noblica commented 3 years ago

Do you think it makes sense to add these 2 types in there as well?

  export type PrismicLink = {
    url: string;
    __typename: string;
  };

  export type PrismicImage = {
    alt: string;
    copyright: string;
    dimensions: {
      width: number;
      height: number;
    };
    url: string;
  };

You can use them when getting data from prismic, to type your response.

hypervillain commented 3 years ago

@noblica I think it makes sense if prismic-javascript doesn't have these typings already. Let me know when you guys think it's ready, I'll find someone with actual ts experience to review and merge it

codingwithchris commented 3 years ago

@noblica

Do you think it makes sense to add these 2 types in there as well?

  export type PrismicLink = {
    url: string;
    __typename: string;
  };

  export type PrismicImage = {
    alt: string;
    copyright: string;
    dimensions: {
      width: number;
      height: number;
    };
    url: string;
  };

You can use them when getting data from prismic, to type your response.

I believe this it outside of the scope of this repo. This is something you would potentially want to declare in your own project as part of its typings IMHO. It doesn't have anything directly to do with rendering rich text.

noblica commented 3 years ago

Hey @codingwithchris thansk for the feedback. Since this is what the graphql query returns when you query prismic, I think it should be part of either this, or prismic-javascript library. But that's just my suggestion, if people feel that it doesn't belong then I'm fine with not adding it.

@sessa Why would you use an enum Elements instead of something like: type Elements = 'heading1' | 'heading2' | 'heading3' | ... ?

ohlr commented 3 years ago

@hypervillain looking forward to the merge - please note that the typings need to be moved out of the subfolder to the root level to be picked up by editors like VSCode

MarcMcIntosh commented 3 years ago

HI, Thanks for the PR and code suggestions :) I've made a PR here https://github.com/prismicio/prismic-reactjs/pull/66 Let me know if there anything else you would like added before I submit it for review.