Closed7

Notion公式ライブラリで取得したデータのプロパティがサジェストで全部出てこずにエラー出す問題の解決

ピン留めされたアイテム
泡沫京水泡沫京水
src/client/notion.ts
import { Client } from "@notionhq/client";
const NotionClient = new Client({auth: process.env.NOTION_SECRET as string})
export default NotionClient
src/Component/NotionPage.tsx
import Notionclient from "@/client/notion";

export default function NotionPage(){
    Notionclient.databases.query({
        database_id: process.env.DATABASE_ID as string,
        "sorts":[
            {
                property: "~~",
                direction: "descending"
            }
        ]
    }).then((res)=> {
        for(let i in res.results){
            console.log(res.results[0])
        }
    })
    return (<p>TEST</p>)
}

このとき、res.results[0]のプロパティは、idobjectしか持っていない状態になっている。しかし、console.log(res.results[0])を実行すると、より多くのプロパティが出現する。つまり、実際に返ってくるデータとデータの型定義が矛盾していることがわかる。

ピン留めされたアイテム
泡沫京水泡沫京水

ライブラリの中身こんな感じにいじってください

node_modules/@notionhq/client/build/src/api-endpoints.d.ts
・・・
export type QueryDatabaseResponse = {
    type: "page";
    page: EmptyObject;
    object: "list";
    next_cursor: string | null;
    has_more: boolean;
    results: Array<PageObjectResponse>;
}
・・・

何をしているかというと、resultsの定義である、Array<PageObjectResponse | PartialPageObjectResponse>| PartialPageObjectResponseを消去する
これをすると、プロパティがしっかり全部出てくる

泡沫京水泡沫京水

注意

ライブラリ自体の型定義を変更するのは、実際かなり無理やりな実装であるため、推奨しない。
(ライブラリをnpmやらyarnから引っ張ってくるたびにいちいち変更しないといけないかも)
また、この実装自体、かなり緩い型定義であるため、これがベストというわけでもない。
この型定義を参考に、可能であればより厳密な型定義を実装するのがベスト。

泡沫京水泡沫京水

代替案、ご指摘等あれば遠慮なくこのスクラップに投稿してください!!

nikogolinikogoli

以下のように「PageObjectResponse には存在して PartialPageObjectResponse には存在しないプロパティ」があることを if を使ってチェックすることで、PageObjectResponse のプロパティにアクセスできるようになります。

export default function NotionPage(){
    Notionclient.databases.query({
        //...
    }).then((res)=> {
        res.results.forEach(result => {
            if ("properties" in result){
                // 以降は型が PageObjectResponse に限定される
                console.log(result.url)
            }
        })
    })
    return (<p>TEST</p>)
}

これはどのクエリでも同様で、blocks.children.list() でページの中身を取得した場合も以下のようにプロパティをチェックして PartialBlockObjectResponse の型を弾くことになります。

await notion.blocks.children.list({block_id: id}).then(res => {
  res.results.forEach(block => {
   if ("type" in block){ // type の存在をチェックしないと .type へのアクセスが型エラーになる
      if (block.type=="heading_1") { /*...*/ }
      else if (block.type=="paragraph") { /*...*/ }
    }
  })
})

Notion API の型は、他にも~~Response型のオブジェクトが~~Request型のオブジェクトとして使えないことがあるなど厄介な部分が多いので、真面目に動かすのは結構大変です。

泡沫京水泡沫京水

なるほど、取得したデータを条件分岐で中身を調べることによって型を確定させるのですね!
アドバイスありがとうございます!やってみます!!

泡沫京水泡沫京水

問題が解決したのでクローズしました。
nikogoliさんの投稿を参考に
皆さんもやってみてください

このスクラップは2023/04/29にクローズされました