Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about new typings #219

Closed
JClackett opened this issue Oct 20, 2021 · 19 comments
Closed

Question about new typings #219

JClackett opened this issue Oct 20, 2021 · 19 comments
Labels
enhancement New feature or request typescript Type system specific issue

Comments

@JClackett
Copy link

I see that the individual block types have been removed and replaced with a large generic union on the responses of some queries.

for example (have removed some properties for clarity):

ListBlockChildrenResponse["results"] = Array<
           {
              type: "paragraph";
              ...stuff
             } | { 
              type: "heading_1";
             ...stuff

... and so on

So a Block I guess can now be represented by:

export type Block = ListBlockChildrenResponse["results"][0]

The same goes for the Database type

export type Database = QueryDatabaseResponse["results"][0]

But when I have a database that has properties on it like "Name" or "Slug", how do I correctly extend the properties type so that its possible to access it without TS complaining, before I could do something like:

const name = (database.properties.Name as TitlePropertyValue).title[0].plain_text

But now that the TitlePropertyValue type doesn't exist, not really sure to handle the custom properties?

Any ideas?

Thanks

@JClackett
Copy link
Author

Also, I used to have a React component that could render out the RichTextBlock like below:

import * as React from "react"
import { Text, Link, StyleProps } from "@chakra-ui/react"
import type { Annotations, RichText } from "@notionhq/client/build/src/api-types"

interface RichTextBlockProps {
  text: RichText[]
}

export function RichTextBlock(props: RichTextBlockProps) {
  const textDecorationAttr = React.useCallback((annotations: Annotations): Omit<StyleProps, "apply"> => {
    return {
      fontWeight: annotations.bold ? 600 : undefined,
      textDecor: `${annotations.underline ? "underline " : ""}${
        annotations.strikethrough ? "line-through" : ""
      }`,
      fontStyle: annotations.italic ? "italic" : undefined,
    }
  }, [])

  if (props.text.length === 0) return <br />
  return (
    <>
      {props.text.map((text, i) => {
        if (text.href) {
          return (
            <Link
              key={i}
              href={text.href}
              isExternal
              color="gray.600"
              _hover={{ color: "gray.900" }}
              {...textDecorationAttr(text.annotations)}
              textDecor="underline"
            >
              {text.plain_text}
            </Link>
          )
        } else {
          return (
            <Text as="span" key={i} {...textDecorationAttr(text.annotations)}>
              {text.plain_text}
            </Text>
          )
        }
      })}
    </>
  )
}

Which was super nice as I could just import the "RichText" type, now it seems I have to manually copy it from your types file:

type RichText = {
  type: "text"
  text: {
    content: string
    link: {
      url: string
    } | null
  }
  annotations: {
    bold: boolean
    italic: boolean
    strikethrough: boolean
    underline: boolean
    code: boolean
    color:
      | "default"
      | "gray"
      | "brown"
      | "orange"
      | "yellow"
      | "green"
      | "blue"
      | "purple"
      | "pink"
      | "red"
      | "gray_background"
      | "brown_background"
      | "orange_background"
      | "yellow_background"
      | "green_background"
      | "blue_background"
      | "purple_background"
      | "pink_background"
      | "red_background"
  }
  plain_text: string
  href: string | null
}

@nartc
Copy link

nartc commented Oct 21, 2021

You can extract more to grt what you need. Check this out to see how I do it: https://github.com/nartc/notion-stuff/blob/6e22fbffafb528e41cc31258c34b5234048ebb25/libs/v4-types/src/lib/types.ts#L6

@peetjvv
Copy link

peetjvv commented Oct 22, 2021

I'm also finding the removal/change of these types frustrating. Was really nice to just be able to import them directly.

@ghost
Copy link

ghost commented Nov 4, 2021

This made the client much much harder to work with when using typescript.
Also the type hints that you get from visual code etc is more or less unreadable :/

@alfdahlman
Copy link

Also finding this frustrating :(

@bitabs
Copy link

bitabs commented Nov 9, 2021

I was actually trying to build their types from scratch for them and raise a PR, but its extremely long

@JClackett
Copy link
Author

I'm assuming they auto generated them?

@rhart92
Copy link
Contributor

rhart92 commented Nov 10, 2021

Apologies for the inconvenience of the new types. In an effort to provide a more accurate and up to date set of types we started auto-generating the types directly from our codebase but in the process we have made the types less ergonomic to work with. In the meantime, using the strategy suggested by @nartc should work to get access to specific block types as shown below:

import { GetBlockResponse } from './api-endpoints'

type HeadingOneBlockResponse = Extract<GetBlockResponse, { type: "heading_1"}>
type ImageBlockResponse = Extract<GetBlockResponse, { type: "image"}>

Note: The types will be slightly different for each endpoint request/responses. For example all responses will have type as required since it's alway returned, but it's optional for all requests. Another example difference is when appending blocks, you're able to add children, but when updating blocks, you can't.

@toolness
Copy link
Contributor

Thanks @rhart92! I think this workaround is nice.

However, I wanted to note that a major problem I'm having with the latest typings is that they appear to be so large that my VSCode refuses to allow me to introspect them in the way that I'm used to.

For example, here's a snippet of code that I'd like to explore:

import notion from "@notionhq/client";

const client = new notion.Client({});

const stuff = await client.databases.query({
    database_id: "fake"
});

console.log(stuff);

Version 0.3.3

Using VSCode with version 0.3.3 of @notionhq/client, hovering my mouse over stuff reveals that it is of type DatabasesQueryResponse:

image

Furthermore, if I right-click on the variable and choose "Go to Type Definition", I am taken to the data type's definition in api-endpoints.d.ts, which leads me to more types which I can easily explore by right-clicking on them and choosing "Go to Definition". This is a great learning tool for me and it's how I explore many libraries.

It also looks like version 0.3.3 has reasonably-sized typings:

$ du -c -h node_modules/@notionhq/client/build/src/*.d.ts

8.0K	node_modules/@notionhq/client/build/src/Client.d.ts
 16K	node_modules/@notionhq/client/build/src/api-endpoints.d.ts
 28K	node_modules/@notionhq/client/build/src/api-types.d.ts
4.0K	node_modules/@notionhq/client/build/src/errors.d.ts
4.0K	node_modules/@notionhq/client/build/src/fetch-types.d.ts
4.0K	node_modules/@notionhq/client/build/src/helpers.d.ts
4.0K	node_modules/@notionhq/client/build/src/index.d.ts
4.0K	node_modules/@notionhq/client/build/src/logging.d.ts
4.0K	node_modules/@notionhq/client/build/src/type-utils.d.ts
 76K	total

Version 0.4.0

Now let's fast-forward to version 0.4.0 of the same library. Now right-clicking on stuff and choosing "Go to Type Definition" still works, but it takes a few seconds for VSCode to show me the file.

I think this is because the typings are much larger in 0.4.0:

$ du -c -h node_modules/@notionhq/client/build/src/*.d.ts

8.0K	node_modules/@notionhq/client/build/src/Client.d.ts
868K	node_modules/@notionhq/client/build/src/api-endpoints.d.ts
4.0K	node_modules/@notionhq/client/build/src/errors.d.ts
4.0K	node_modules/@notionhq/client/build/src/fetch-types.d.ts
4.0K	node_modules/@notionhq/client/build/src/helpers.d.ts
4.0K	node_modules/@notionhq/client/build/src/index.d.ts
4.0K	node_modules/@notionhq/client/build/src/logging.d.ts
4.0K	node_modules/@notionhq/client/build/src/type-utils.d.ts
900K	total

Version 0.4.6

Now let's go to the very latest version of the library, 0.4.6. At this point, hovering my mouse over stuff shows the tooltip (loading...) const stuff: any for several seconds before it resolves to its actual type. But what's really unfortunate is that right-clicking on the symbol and choosing "Go to Type Definition" doesn't work at all:

image

I suspect this is because the typings have now become even larger:

$ du -c -h node_modules/@notionhq/client/build/src/*.d.ts

8.0K	node_modules/@notionhq/client/build/src/Client.d.ts
6.6M	node_modules/@notionhq/client/build/src/api-endpoints.d.ts
4.0K	node_modules/@notionhq/client/build/src/errors.d.ts
4.0K	node_modules/@notionhq/client/build/src/fetch-types.d.ts
4.0K	node_modules/@notionhq/client/build/src/helpers.d.ts
4.0K	node_modules/@notionhq/client/build/src/index.d.ts
4.0K	node_modules/@notionhq/client/build/src/logging.d.ts
4.0K	node_modules/@notionhq/client/build/src/type-utils.d.ts
6.6M	total

My guess is that TypeScript is seeing that api-endpoints.d.ts is 6.6 megabytes and simply refusing to take me there, but I'm not sure. I'm also guessing that these huge typings have an effect on the performance of the TypeScript compiler, both in its speed and memory use, but I haven't done any work to verify that.

In any case, it would be great if the typings could be nice and small again, as it would likely bring back the great developer ergonomics that version 0.3.3 had.

@toolness
Copy link
Contributor

Good news--it looks like the latest release, 0.4.8, has slimmed down the api-endpoints.d.ts file to 2.2 megabytes (in particular, an EmojiRequest type is now declared once and reused in many places, instead of being inlined everywhere). This makes my VSCode show me type definitions once more, which is great! Though further slimming of the SDK would be quite appreciated for the reasons mentioned in my previous comment.

@loicortola
Copy link

Hi @rhart92 ,

thanks for the work on the client.
I see some comments about the fact that the code-generation trade-offs kind of kills DX in Typescript, just wanted to know if there was a roadmap to improve that in the future? (To implement better composition and more modularity rather than just exhaustive structure)?

Thank you for your clarifications :)

JohannesRudolph referenced this issue in meshcloud/notion-markdown-cms Jan 10, 2022
@Niceplace
Copy link

Niceplace commented Jan 19, 2022

@rhart92 First of all, I want to say that I absolutely LOVE being able to use the notion API, let alone having an SDK for it. Thank you for your (and your colleague's) hard work on this, I'm sure it's no easy task !

I want to explain my understanding of my current problem with a simple example first and then explain my use case. I tried to see how I can apply your workaround with Extract<> but I'm not good enough with Typescript yet to understand how to do that with an Array of Union types. I searched as much as I could but I'm struggling here.

I'm using the SDK @ version 0.4.12 with typescript 4.5.4

Typescript Example

I seem to notice a fundamental problem with the way some types seem to be generated, especially with how Union types are designed within Typescript. It took me a while to get to the root of the problem and I learned something new so there's that :D

From the Handbook

TypeScript will only allow an operation if it is valid for every member of the union. For example, if you have the union string | number, you can’t use methods that are only available on string:

This constraint is better explained with the example below

type GetAllPeople = () => { results: Array<{ name: string, age: number} | { age: number}>}
type GetAllPeopleReturnType = ReturnType<GetAllPeople>['results']

const someArray: GetAllPeople = [{ name: 'Simon', age: 30 }, [{ age: 22}]
 // Will autocomplete and TS is happy
const allAges = someArray.map(element => element.age)
// Will not autocomplete and TS will complain because the property 'name' is not applicable 
//    to every member of Array<{ name: string, age: number} | { age: number}>
const allNames = someArray.map(element => element.name) 

Use Case with QueryDatabaseResponse

I am using the QueryDatabaseResponse type is exported in auto-generated types in: @notionhq/client/build/src/api-endpoints
I build a little helper function to help me handle pagination automatically and I only need to feed it the parameters for the query function.

The return value's type is QueryDatabaseResponse['results'] which I am extracting from the return type of databases.query -> Awaited<ReturnType<typeof query>>['results'].

/**
 * Query all pages and return all records from a Notion database object
 *  Will log a warning if database has no records
 * @param parameters To specify database id, control sorting, filtering and pagination, directly using Notion's sdk types
 * @returns A list of all the results from the database or an empty array
 */
export const queryAll = async (
  parameters: QueryDatabaseParameters,
) => {
  const params: typeof parameters = { ...parameters };
  // getNotionClient() returns an authenticated instance of the notion SDK 
  const query = getNotionClient().databases.query;
  const allResults: Awaited<ReturnType<typeof query>>['results'] = [];

  let hasNextPage = true;
  while (hasNextPage) {
    const currentPage = await query(params);
    allResults.push(...currentPage.results);
    hasNextPage = currentPage.has_more;
    params.start_cursor = currentPage.next_cursor || undefined; // next_cursor is string | null while params.start_cursor is string | undefined -.-
  }
  if (!allResults.length) {
    logger.warn(`No results found in database ${params.database_id}`);
  }
  return allResults;
};

Unfortunately, it seems that the type of allResults is stuck to { id: string; object: 'page'}[] while the generated type for a database response (included in an expandable toggle right below) seem to indicate that the results property can be a lot of things. I'm unsure how to pick the right one, I would rather have the SDK infer it correctly based on the responses' contents but I don't know if that's even doable given the complexity and possible permutations of objects we can have in a Database.

Thoughts ? :/

CLICK TO EXPAND -Generated type definition for QueryDatabaseResponse
export declare type QueryDatabaseResponse = {
    type: "rollup";
    rollup: {
        type: "number";
        number: number | null;
        function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
    } | {
        type: "date";
        date: {
            start: string;
            end: string | null;
            time_zone: TimeZoneRequest | null;
        } | null;
        function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
    } | {
        type: "array";
        array: Array<{
            type: "title";
            title: Array<{
                type: "text";
                text: {
                    content: string;
                    link: {
                        url: TextRequest;
                    } | null;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "mention";
                mention: {
                    type: "user";
                    user: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    };
                } | {
                    type: "link_preview";
                    link_preview: {
                        url: TextRequest;
                    };
                } | {
                    type: "page";
                    page: {
                        id: IdRequest;
                    };
                } | {
                    type: "database";
                    database: {
                        id: IdRequest;
                    };
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "equation";
                equation: {
                    expression: TextRequest;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            }>;
        } | {
            type: "rich_text";
            rich_text: Array<{
                type: "text";
                text: {
                    content: string;
                    link: {
                        url: TextRequest;
                    } | null;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "mention";
                mention: {
                    type: "user";
                    user: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    };
                } | {
                    type: "link_preview";
                    link_preview: {
                        url: TextRequest;
                    };
                } | {
                    type: "page";
                    page: {
                        id: IdRequest;
                    };
                } | {
                    type: "database";
                    database: {
                        id: IdRequest;
                    };
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "equation";
                equation: {
                    expression: TextRequest;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            }>;
        } | {
            type: "number";
            number: number | null;
        } | {
            type: "url";
            url: string | null;
        } | {
            type: "select";
            select: {
                id: StringRequest;
                name: StringRequest;
                color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
            } | null;
        } | {
            type: "multi_select";
            multi_select: Array<{
                id: StringRequest;
                name: StringRequest;
                color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
            }>;
        } | {
            type: "people";
            people: Array<{
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            }>;
        } | {
            type: "email";
            email: string | null;
        } | {
            type: "phone_number";
            phone_number: string | null;
        } | {
            type: "date";
            date: {
                start: string;
                end: string | null;
                time_zone: TimeZoneRequest | null;
            } | null;
        } | {
            type: "files";
            files: Array<{
                file: {
                    url: string;
                    expiry_time: string;
                };
                name: StringRequest;
                type?: "file";
            } | {
                external: {
                    url: TextRequest;
                };
                name: StringRequest;
                type?: "external";
            }>;
        } | {
            type: "checkbox";
            checkbox: boolean;
        } | {
            type: "formula";
            formula: {
                type: "string";
                string: string | null;
            } | {
                type: "date";
                date: {
                    start: string;
                    end: string | null;
                    time_zone: TimeZoneRequest | null;
                } | null;
            } | {
                type: "number";
                number: number | null;
            } | {
                type: "boolean";
                boolean: boolean | null;
            };
        } | {
            type: "relation";
            relation: Array<{
                id: string;
            }>;
        } | {
            type: "created_time";
            created_time: string;
        } | {
            type: "created_by";
            created_by: {
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            };
        } | {
            type: "last_edited_time";
            last_edited_time: string;
        } | {
            type: "last_edited_by";
            last_edited_by: {
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            };
        }>;
        function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
    } | {
        type: "unsupported";
        unsupported: EmptyObject;
        function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
    };
    object: "list";
    results: Array<{
        parent: {
            type: "database_id";
            database_id: IdRequest;
        } | {
            type: "page_id";
            page_id: IdRequest;
        } | {
            type: "workspace";
            workspace: true;
        };
        properties: Record<string, {
            type: "title";
            title: Array<{
                type: "text";
                text: {
                    content: string;
                    link: {
                        url: TextRequest;
                    } | null;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "mention";
                mention: {
                    type: "user";
                    user: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    };
                } | {
                    type: "link_preview";
                    link_preview: {
                        url: TextRequest;
                    };
                } | {
                    type: "page";
                    page: {
                        id: IdRequest;
                    };
                } | {
                    type: "database";
                    database: {
                        id: IdRequest;
                    };
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "equation";
                equation: {
                    expression: TextRequest;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            }>;
            id: string;
        } | {
            type: "rich_text";
            rich_text: Array<{
                type: "text";
                text: {
                    content: string;
                    link: {
                        url: TextRequest;
                    } | null;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "mention";
                mention: {
                    type: "user";
                    user: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    };
                } | {
                    type: "link_preview";
                    link_preview: {
                        url: TextRequest;
                    };
                } | {
                    type: "page";
                    page: {
                        id: IdRequest;
                    };
                } | {
                    type: "database";
                    database: {
                        id: IdRequest;
                    };
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "equation";
                equation: {
                    expression: TextRequest;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            }>;
            id: string;
        } | {
            type: "number";
            number: number | null;
            id: string;
        } | {
            type: "url";
            url: string | null;
            id: string;
        } | {
            type: "select";
            select: {
                id: StringRequest;
                name: StringRequest;
                color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
            } | null;
            id: string;
        } | {
            type: "multi_select";
            multi_select: Array<{
                id: StringRequest;
                name: StringRequest;
                color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
            }>;
            id: string;
        } | {
            type: "people";
            people: Array<{
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            }>;
            id: string;
        } | {
            type: "email";
            email: string | null;
            id: string;
        } | {
            type: "phone_number";
            phone_number: string | null;
            id: string;
        } | {
            type: "date";
            date: {
                start: string;
                end: string | null;
                time_zone: TimeZoneRequest | null;
            } | null;
            id: string;
        } | {
            type: "files";
            files: Array<{
                file: {
                    url: string;
                    expiry_time: string;
                };
                name: StringRequest;
                type?: "file";
            } | {
                external: {
                    url: TextRequest;
                };
                name: StringRequest;
                type?: "external";
            }>;
            id: string;
        } | {
            type: "checkbox";
            checkbox: boolean;
            id: string;
        } | {
            type: "formula";
            formula: {
                type: "string";
                string: string | null;
            } | {
                type: "date";
                date: {
                    start: string;
                    end: string | null;
                    time_zone: TimeZoneRequest | null;
                } | null;
            } | {
                type: "number";
                number: number | null;
            } | {
                type: "boolean";
                boolean: boolean | null;
            };
            id: string;
        } | {
            type: "relation";
            relation: Array<{
                id: string;
            }>;
            id: string;
        } | {
            type: "created_time";
            created_time: string;
            id: string;
        } | {
            type: "created_by";
            created_by: {
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            };
            id: string;
        } | {
            type: "last_edited_time";
            last_edited_time: string;
            id: string;
        } | {
            type: "last_edited_by";
            last_edited_by: {
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            };
            id: string;
        } | {
            type: "rollup";
            rollup: {
                type: "number";
                number: number | null;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            } | {
                type: "date";
                date: {
                    start: string;
                    end: string | null;
                    time_zone: TimeZoneRequest | null;
                } | null;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            } | {
                type: "array";
                array: Array<{
                    type: "title";
                    title: Array<{
                        type: "text";
                        text: {
                            content: string;
                            link: {
                                url: TextRequest;
                            } | null;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "mention";
                        mention: {
                            type: "user";
                            user: {
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "person";
                                person: {
                                    email?: string;
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "bot";
                                bot: EmptyObject | {
                                    owner: {
                                        type: "user";
                                        user: {
                                            type: "person";
                                            person: {
                                                email: string;
                                            };
                                            name: string | null;
                                            avatar_url: string | null;
                                            id: IdRequest;
                                            object: "user";
                                        } | {
                                            id: IdRequest;
                                            object: "user";
                                        };
                                    } | {
                                        type: "workspace";
                                        workspace: true;
                                    };
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            };
                        } | {
                            type: "date";
                            date: {
                                start: string;
                                end: string | null;
                                time_zone: TimeZoneRequest | null;
                            };
                        } | {
                            type: "link_preview";
                            link_preview: {
                                url: TextRequest;
                            };
                        } | {
                            type: "page";
                            page: {
                                id: IdRequest;
                            };
                        } | {
                            type: "database";
                            database: {
                                id: IdRequest;
                            };
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "equation";
                        equation: {
                            expression: TextRequest;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    }>;
                } | {
                    type: "rich_text";
                    rich_text: Array<{
                        type: "text";
                        text: {
                            content: string;
                            link: {
                                url: TextRequest;
                            } | null;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "mention";
                        mention: {
                            type: "user";
                            user: {
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "person";
                                person: {
                                    email?: string;
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "bot";
                                bot: EmptyObject | {
                                    owner: {
                                        type: "user";
                                        user: {
                                            type: "person";
                                            person: {
                                                email: string;
                                            };
                                            name: string | null;
                                            avatar_url: string | null;
                                            id: IdRequest;
                                            object: "user";
                                        } | {
                                            id: IdRequest;
                                            object: "user";
                                        };
                                    } | {
                                        type: "workspace";
                                        workspace: true;
                                    };
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            };
                        } | {
                            type: "date";
                            date: {
                                start: string;
                                end: string | null;
                                time_zone: TimeZoneRequest | null;
                            };
                        } | {
                            type: "link_preview";
                            link_preview: {
                                url: TextRequest;
                            };
                        } | {
                            type: "page";
                            page: {
                                id: IdRequest;
                            };
                        } | {
                            type: "database";
                            database: {
                                id: IdRequest;
                            };
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "equation";
                        equation: {
                            expression: TextRequest;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    }>;
                } | {
                    type: "number";
                    number: number | null;
                } | {
                    type: "url";
                    url: string | null;
                } | {
                    type: "select";
                    select: {
                        id: StringRequest;
                        name: StringRequest;
                        color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
                    } | null;
                } | {
                    type: "multi_select";
                    multi_select: Array<{
                        id: StringRequest;
                        name: StringRequest;
                        color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
                    }>;
                } | {
                    type: "people";
                    people: Array<{
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    }>;
                } | {
                    type: "email";
                    email: string | null;
                } | {
                    type: "phone_number";
                    phone_number: string | null;
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    } | null;
                } | {
                    type: "files";
                    files: Array<{
                        file: {
                            url: string;
                            expiry_time: string;
                        };
                        name: StringRequest;
                        type?: "file";
                    } | {
                        external: {
                            url: TextRequest;
                        };
                        name: StringRequest;
                        type?: "external";
                    }>;
                } | {
                    type: "checkbox";
                    checkbox: boolean;
                } | {
                    type: "formula";
                    formula: {
                        type: "string";
                        string: string | null;
                    } | {
                        type: "date";
                        date: {
                            start: string;
                            end: string | null;
                            time_zone: TimeZoneRequest | null;
                        } | null;
                    } | {
                        type: "number";
                        number: number | null;
                    } | {
                        type: "boolean";
                        boolean: boolean | null;
                    };
                } | {
                    type: "relation";
                    relation: Array<{
                        id: string;
                    }>;
                } | {
                    type: "created_time";
                    created_time: string;
                } | {
                    type: "created_by";
                    created_by: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "last_edited_time";
                    last_edited_time: string;
                } | {
                    type: "last_edited_by";
                    last_edited_by: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                }>;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            } | {
                type: "unsupported";
                unsupported: EmptyObject;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            };
            id: string;
        }>;
        icon: {
            type: "emoji";
            emoji: EmojiRequest;
        } | null | {
            type: "external";
            external: {
                url: TextRequest;
            };
        } | null | {
            type: "file";
            file: {
                url: string;
                expiry_time: string;
            };
        } | null;
        cover: {
            type: "external";
            external: {
                url: TextRequest;
            };
        } | null | {
            type: "file";
            file: {
                url: string;
                expiry_time: string;
            };
        } | null;
        object: "page";
        id: string;
        created_time: string;
        last_edited_time: string;
        archived: boolean;
        url: string;
    } | {
        object: "page";
        id: string;
    }>;
    next_cursor: string | null;
    has_more: boolean;
} | {
    object: "list";
    results: Array<{
        parent: {
            type: "database_id";
            database_id: IdRequest;
        } | {
            type: "page_id";
            page_id: IdRequest;
        } | {
            type: "workspace";
            workspace: true;
        };
        properties: Record<string, {
            type: "title";
            title: Array<{
                type: "text";
                text: {
                    content: string;
                    link: {
                        url: TextRequest;
                    } | null;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "mention";
                mention: {
                    type: "user";
                    user: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    };
                } | {
                    type: "link_preview";
                    link_preview: {
                        url: TextRequest;
                    };
                } | {
                    type: "page";
                    page: {
                        id: IdRequest;
                    };
                } | {
                    type: "database";
                    database: {
                        id: IdRequest;
                    };
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "equation";
                equation: {
                    expression: TextRequest;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            }>;
            id: string;
        } | {
            type: "rich_text";
            rich_text: Array<{
                type: "text";
                text: {
                    content: string;
                    link: {
                        url: TextRequest;
                    } | null;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "mention";
                mention: {
                    type: "user";
                    user: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    };
                } | {
                    type: "link_preview";
                    link_preview: {
                        url: TextRequest;
                    };
                } | {
                    type: "page";
                    page: {
                        id: IdRequest;
                    };
                } | {
                    type: "database";
                    database: {
                        id: IdRequest;
                    };
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            } | {
                type: "equation";
                equation: {
                    expression: TextRequest;
                };
                annotations: {
                    bold: boolean;
                    italic: boolean;
                    strikethrough: boolean;
                    underline: boolean;
                    code: boolean;
                    color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                };
                plain_text: string;
                href: string | null;
            }>;
            id: string;
        } | {
            type: "number";
            number: number | null;
            id: string;
        } | {
            type: "url";
            url: string | null;
            id: string;
        } | {
            type: "select";
            select: {
                id: StringRequest;
                name: StringRequest;
                color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
            } | null;
            id: string;
        } | {
            type: "multi_select";
            multi_select: Array<{
                id: StringRequest;
                name: StringRequest;
                color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
            }>;
            id: string;
        } | {
            type: "people";
            people: Array<{
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            }>;
            id: string;
        } | {
            type: "email";
            email: string | null;
            id: string;
        } | {
            type: "phone_number";
            phone_number: string | null;
            id: string;
        } | {
            type: "date";
            date: {
                start: string;
                end: string | null;
                time_zone: TimeZoneRequest | null;
            } | null;
            id: string;
        } | {
            type: "files";
            files: Array<{
                file: {
                    url: string;
                    expiry_time: string;
                };
                name: StringRequest;
                type?: "file";
            } | {
                external: {
                    url: TextRequest;
                };
                name: StringRequest;
                type?: "external";
            }>;
            id: string;
        } | {
            type: "checkbox";
            checkbox: boolean;
            id: string;
        } | {
            type: "formula";
            formula: {
                type: "string";
                string: string | null;
            } | {
                type: "date";
                date: {
                    start: string;
                    end: string | null;
                    time_zone: TimeZoneRequest | null;
                } | null;
            } | {
                type: "number";
                number: number | null;
            } | {
                type: "boolean";
                boolean: boolean | null;
            };
            id: string;
        } | {
            type: "relation";
            relation: Array<{
                id: string;
            }>;
            id: string;
        } | {
            type: "created_time";
            created_time: string;
            id: string;
        } | {
            type: "created_by";
            created_by: {
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            };
            id: string;
        } | {
            type: "last_edited_time";
            last_edited_time: string;
            id: string;
        } | {
            type: "last_edited_by";
            last_edited_by: {
                id: IdRequest;
                object: "user";
            } | {
                type: "person";
                person: {
                    email?: string;
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            } | {
                type: "bot";
                bot: EmptyObject | {
                    owner: {
                        type: "user";
                        user: {
                            type: "person";
                            person: {
                                email: string;
                            };
                            name: string | null;
                            avatar_url: string | null;
                            id: IdRequest;
                            object: "user";
                        } | {
                            id: IdRequest;
                            object: "user";
                        };
                    } | {
                        type: "workspace";
                        workspace: true;
                    };
                };
                name: string | null;
                avatar_url: string | null;
                id: IdRequest;
                object: "user";
            };
            id: string;
        } | {
            type: "rollup";
            rollup: {
                type: "number";
                number: number | null;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            } | {
                type: "date";
                date: {
                    start: string;
                    end: string | null;
                    time_zone: TimeZoneRequest | null;
                } | null;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            } | {
                type: "array";
                array: Array<{
                    type: "title";
                    title: Array<{
                        type: "text";
                        text: {
                            content: string;
                            link: {
                                url: TextRequest;
                            } | null;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "mention";
                        mention: {
                            type: "user";
                            user: {
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "person";
                                person: {
                                    email?: string;
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "bot";
                                bot: EmptyObject | {
                                    owner: {
                                        type: "user";
                                        user: {
                                            type: "person";
                                            person: {
                                                email: string;
                                            };
                                            name: string | null;
                                            avatar_url: string | null;
                                            id: IdRequest;
                                            object: "user";
                                        } | {
                                            id: IdRequest;
                                            object: "user";
                                        };
                                    } | {
                                        type: "workspace";
                                        workspace: true;
                                    };
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            };
                        } | {
                            type: "date";
                            date: {
                                start: string;
                                end: string | null;
                                time_zone: TimeZoneRequest | null;
                            };
                        } | {
                            type: "link_preview";
                            link_preview: {
                                url: TextRequest;
                            };
                        } | {
                            type: "page";
                            page: {
                                id: IdRequest;
                            };
                        } | {
                            type: "database";
                            database: {
                                id: IdRequest;
                            };
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "equation";
                        equation: {
                            expression: TextRequest;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    }>;
                } | {
                    type: "rich_text";
                    rich_text: Array<{
                        type: "text";
                        text: {
                            content: string;
                            link: {
                                url: TextRequest;
                            } | null;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "mention";
                        mention: {
                            type: "user";
                            user: {
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "person";
                                person: {
                                    email?: string;
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            } | {
                                type: "bot";
                                bot: EmptyObject | {
                                    owner: {
                                        type: "user";
                                        user: {
                                            type: "person";
                                            person: {
                                                email: string;
                                            };
                                            name: string | null;
                                            avatar_url: string | null;
                                            id: IdRequest;
                                            object: "user";
                                        } | {
                                            id: IdRequest;
                                            object: "user";
                                        };
                                    } | {
                                        type: "workspace";
                                        workspace: true;
                                    };
                                };
                                name: string | null;
                                avatar_url: string | null;
                                id: IdRequest;
                                object: "user";
                            };
                        } | {
                            type: "date";
                            date: {
                                start: string;
                                end: string | null;
                                time_zone: TimeZoneRequest | null;
                            };
                        } | {
                            type: "link_preview";
                            link_preview: {
                                url: TextRequest;
                            };
                        } | {
                            type: "page";
                            page: {
                                id: IdRequest;
                            };
                        } | {
                            type: "database";
                            database: {
                                id: IdRequest;
                            };
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    } | {
                        type: "equation";
                        equation: {
                            expression: TextRequest;
                        };
                        annotations: {
                            bold: boolean;
                            italic: boolean;
                            strikethrough: boolean;
                            underline: boolean;
                            code: boolean;
                            color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red" | "gray_background" | "brown_background" | "orange_background" | "yellow_background" | "green_background" | "blue_background" | "purple_background" | "pink_background" | "red_background";
                        };
                        plain_text: string;
                        href: string | null;
                    }>;
                } | {
                    type: "number";
                    number: number | null;
                } | {
                    type: "url";
                    url: string | null;
                } | {
                    type: "select";
                    select: {
                        id: StringRequest;
                        name: StringRequest;
                        color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
                    } | null;
                } | {
                    type: "multi_select";
                    multi_select: Array<{
                        id: StringRequest;
                        name: StringRequest;
                        color: "default" | "gray" | "brown" | "orange" | "yellow" | "green" | "blue" | "purple" | "pink" | "red";
                    }>;
                } | {
                    type: "people";
                    people: Array<{
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    }>;
                } | {
                    type: "email";
                    email: string | null;
                } | {
                    type: "phone_number";
                    phone_number: string | null;
                } | {
                    type: "date";
                    date: {
                        start: string;
                        end: string | null;
                        time_zone: TimeZoneRequest | null;
                    } | null;
                } | {
                    type: "files";
                    files: Array<{
                        file: {
                            url: string;
                            expiry_time: string;
                        };
                        name: StringRequest;
                        type?: "file";
                    } | {
                        external: {
                            url: TextRequest;
                        };
                        name: StringRequest;
                        type?: "external";
                    }>;
                } | {
                    type: "checkbox";
                    checkbox: boolean;
                } | {
                    type: "formula";
                    formula: {
                        type: "string";
                        string: string | null;
                    } | {
                        type: "date";
                        date: {
                            start: string;
                            end: string | null;
                            time_zone: TimeZoneRequest | null;
                        } | null;
                    } | {
                        type: "number";
                        number: number | null;
                    } | {
                        type: "boolean";
                        boolean: boolean | null;
                    };
                } | {
                    type: "relation";
                    relation: Array<{
                        id: string;
                    }>;
                } | {
                    type: "created_time";
                    created_time: string;
                } | {
                    type: "created_by";
                    created_by: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                } | {
                    type: "last_edited_time";
                    last_edited_time: string;
                } | {
                    type: "last_edited_by";
                    last_edited_by: {
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "person";
                        person: {
                            email?: string;
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    } | {
                        type: "bot";
                        bot: EmptyObject | {
                            owner: {
                                type: "user";
                                user: {
                                    type: "person";
                                    person: {
                                        email: string;
                                    };
                                    name: string | null;
                                    avatar_url: string | null;
                                    id: IdRequest;
                                    object: "user";
                                } | {
                                    id: IdRequest;
                                    object: "user";
                                };
                            } | {
                                type: "workspace";
                                workspace: true;
                            };
                        };
                        name: string | null;
                        avatar_url: string | null;
                        id: IdRequest;
                        object: "user";
                    };
                }>;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            } | {
                type: "unsupported";
                unsupported: EmptyObject;
                function: "count" | "count_values" | "empty" | "not_empty" | "unique" | "show_unique" | "percent_empty" | "percent_not_empty" | "sum" | "average" | "median" | "min" | "max" | "range" | "earliest_date" | "latest_date" | "date_range" | "checked" | "unchecked" | "percent_checked" | "percent_unchecked" | "show_original";
            };
            id: string;
        }>;
        icon: {
            type: "emoji";
            emoji: EmojiRequest;
        } | null | {
            type: "external";
            external: {
                url: TextRequest;
            };
        } | null | {
            type: "file";
            file: {
                url: string;
                expiry_time: string;
            };
        } | null;
        cover: {
            type: "external";
            external: {
                url: TextRequest;
            };
        } | null | {
            type: "file";
            file: {
                url: string;
                expiry_time: string;
            };
        } | null;
        object: "page";
        id: string;
        created_time: string;
        last_edited_time: string;
        archived: boolean;
        url: string;
    } | {
        object: "page";
        id: string;
    }>;
    next_cursor: string | null;
    has_more: boolean;
};

@danopia
Copy link

danopia commented Jan 19, 2022

I've found that the generate-random-data SDK example shows the same issue with the newer partial-response typings. So here's how I fixed it:

  const queryResponse = await notion.databases.query({
    database_id: databaseId,
  })
  queryResponse.results.forEach(pageIn => {
    // if (pageIn.object) return;
    const page = pageIn as Extract<typeof pageIn, {parent: {}}>;

I really expected the if (page.object) return; check to narrow the union, but it didn't actually change anything in the types so the Extract cast is doing the actual work. I'm not sure if I believe that 'object' isn't always there at this point.

@justjake
Copy link
Contributor

Hello,

I have released my personal Notion API toolkit to NPM here: @jitl/notion-api. This package exports types like Block<BlockType>, Page, RichText, etc derived from the official types exported from this repo (which I recently shrank from 2.2mb to 300kb). @jitl/notion-api also provides utility functions for iterating paginated APIs, narrowing types like GetBlockResponse, and more. See the README section on API helpers.

To re-write @danopia's example with my library:

import { isFullPage, iteratePaginatedAPI } from '@jitl/notion-api';

for await (const page of iteratePaginatedAPI(notion.databases.query, {
  database_id: databaseId,
})) {
  if (isFullPage(page)) {
    // page is a "full" page object
    doThings(page.properties)
  }
}

To re-write @Niceplace's example with my library:

import { isFullPage, iteratePaginatedAPI, asyncIterableToArray } from '@jitl/notion-api';

/**
 * Query all pages and return all records from a Notion database object
 *  Will log a warning if database has no records
 * @param parameters To specify database id, control sorting, filtering and
 *   pagination, directly using Notion's sdk types
 * @returns A list of all the results from the database or an empty array
 */
export const queryAll = async (
  parameters: QueryDatabaseParameters
): Promise<Page[]> => {
  const params: typeof parameters = { ...parameters };
  const resultsWithPartialPages = await asyncIterableToArray(
    // getNotionClient() returns an authenticated instance of the notion SDK
    iteratePaginatedAPI(getNotionClient().databases.query, parameters)
  );

  // Filter out partial pages
  const fullPages = resultsWithPartialPages.filter(isFullPage);

  if (!fullPages.length) {
    logger.warn(`No results found in database ${params.database_id}`);
  }
  return fullPages;
};

@jitl/notion-api is not an official Notion product. I wrote it for my own use, to support my website and other personal projects, although I welcome contributions of any kind.

@jonrimmer
Copy link

I'm experimenting with writing a Notion integration, but I cannot figure out how to use the types generated for search. The API documentation says that the results have properties like created_by, title, etc. But the only properties TS thinks they have is id and object:

image

Even if I check the value of object, I still cannot access any of these metadata fields:

image

Am I missing something?

@justjake
Copy link
Contributor

justjake commented Mar 4, 2022

@jonrimmer there are two types here - “partial” object types, which are returned for objects that an integration can locate, but not access, and “full” object types that have all of the properties referenced in the documentation.

You need to check for the presence of a full-object-only key in the response to prove to Typescript that the object is “full”. This is annoying to do, so I published a helper library (linked in the above post) that exports functions like isFullPage, etc.

From my library’s README:


The Notion API can sometimes return "partial" object data that contain only the block's ID:

// In @notionhq/client typings:
type PartialBlockObjectResponse = { object: 'block'; id: string };
export type GetBlockResponse = PartialBlockObjectResponse | BlockObjectResponse;

Checking that a GetBlockResponse (or similar type) is a "full" block gets old pretty fast, so this library exports type guard functions to handle common cases, like isFullPage(page) and isFullBlock(block).

isFullBlock can optionally narrow the type of block as well:

if (isFullBlock(block, 'paragraph')) {
  // It's a full paragraph block
  console.log(richTextAsPlainText(block.paragraph.text));
}

@Niceplace
Copy link

@jonrimmer This is most likely because of the heavy usage of union types, as explained in my previous comment here: #219 (comment)

It acts like a least common denominator for type properties that you can see.

@sebastiankade
Copy link

sebastiankade commented Jun 27, 2022

This is still a gross situation as of @notionhq/client@1.04 ....

One way to solve is to use @justjake 's @jitl/notion-api as mentioned above, the types are good and utils are helpful. However they are not up to date with latest API types from notion (e.g. status) that have been recently released.

Alternatively if you want to battle your way with pulling out the types from the unions here are some type util helpers:

type ArrayType<ArrType> = ArrType extends readonly (infer ElementType)[]
  ? ElementType
  : never;

export type DatabaseItem = ArrayType<QueryDatabaseResponse["results"]>;
export type Page = Extract<DatabaseItem, { properties: any }>;
export type PageReference = Exclude<DatabaseItem, Page>;

@rhart92 you guys should consider exporting these as helper types as it does take a lot of messing around to start getting value out of the notion database queries atm.

@wcauchois
Copy link
Contributor

Hi, I recently made some changes to name many more response types and export them from this package in #319, so I am going to close this issue. These changes are available in version 2.1.0 of the SDK. If there are any more specific issues around types please open a new GitHub issue, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request typescript Type system specific issue
Projects
None yet
Development

No branches or pull requests

16 participants