動かざることバグの如し

近づきたいよ 君の理想に

GitHub Actionsでgit差分がある時のみコミットする方法

環境

  • actions/checkout@v3

やりたいこと

GitHub ActionsでCI実行後にgit差分があればコミット&pushする。

なければそのまま終了する

どういうとき使うのかって言うと自動定期アップデートとか

コード

- name: Commit updated files
  run: |
    git config core.filemode false
    if ! git diff --exit-code --quiet
    then
      git add -A
      git config user.name thr3a
      git config user.email thr3a@example.com
      git commit -m "Commit updated files"
      git push
    fi

InferGetStaticPropsTypeを使ってnextjsをよりラクラクに

環境

  • nextjs 12.3

InferGetStaticPropsTypeってなに

getStaticPropsの返却値をもとにNextPageに渡されるPropsの型を推論してくれる機能

よくあるgetStaticPropsの例

例えばこんな感じにあったとして

import type { NextPage } from 'next';
import { GetStaticProps } from 'next';

type Repository = {
  id: number
  name: string
  full_name: string,
  description: string
  stargazers_count: number
} & Record<string, unknown>

type Props = { repos: Repository[] };

const Home: NextPage<Props> = ({repos}) => {
  return (
    <>
      { repos.map((repo) => {
        return (
          <p key={repo.id}>{repo.name} / {repo.description}</p>
        );
      })}
    </>
  );
};

export const getStaticProps: GetStaticProps<Props> = async (context) => {
  const res = await fetch('https://api.github.com/users/rails/repos');
  const repos: Repository[] = await res.json();
  return {
    props: {
      repos
    },
  };
};

export default Home;

ただ橋渡し用のPropsである、

type Props = { repos: Repository[] };

ってのが冗長だなと

そこでInferGetStaticPropsTypeを使ってみる 変更点は以下のみ

-type Props = { repos: Repository[] };
+type Props = InferGetStaticPropsType<typeof getStaticProps>;
 
-export const getStaticProps: GetStaticProps<Props> = async (context) => {
+export const getStaticProps = async (context: GetStaticPropsContext) => {

そうすると getStaticProps()は async (context: GetStaticPropsContext) だけのコードになるので 返却するProps変えるごとに橋渡し用のPropsも修正する必要がなくなった。便利

GetStaticPropsContextに置き換えたバージョンの全コード

import type { InferGetStaticPropsType, NextPage, GetStaticPropsContext } from 'next';

type Repository = {
  id: number
  name: string
  full_name: string,
  description: string
  stargazers_count: number
} & Record<string, unknown>

type Props = InferGetStaticPropsType<typeof getStaticProps>;

const Home: NextPage<Props> = ({repos}) => {
  return (
    <>
      { repos.map((repo) => {
        return (
          <p key={repo.id}>{repo.name} / {repo.description}</p>
        );
      })}
    </>
  );
};

export const getStaticProps = async (context: GetStaticPropsContext) => {
  const res = await fetch('https://api.github.com/users/rails/repos');
  const repos: Repository[] = await res.json();
  return {
    props: {
      repos
    },
  };
};

export default Home;

公式ドキュメントよこせ

Data Fetching: getStaticProps | Next.js

サーバーサイド版はないの?

あったわ

InferGetServerSidePropsType

公式のサンプルコードをよこせ

next.js/github.d.ts at canary · vercel/next.js

参考リンク

TypeScriptで配列をグルーピングするgroupBy関数

やりたいこと

JSONとかのJavaScriptオブジェクトの配列があったとき、特定のキーとかでグルーピングしたい

例えば

const list = [
  {
    "name": "taro",
    "role": "admin"
  },
  {
    "name": "jiro",
    "role": "staff"
  },
  {
    "name": "hanako",
    "role": "admin"
  }
];

ってデータが有った場合

{
  "admin": [
    {
      "name": "taro",
      "role": "admin"
    },
    {
      "name": "hanako",
      "role": "admin"
    }
  ],
  "staff": [
    {
      "name": "jiro",
      "role": "staff"
    }
  ]
}

ってやりたい

JavascriptにはgroupBy関数がない

Rubyなら[].group_byで一発なのに。。。ってことで自分で関数を作るしか無い。JavaScriptのサンプルコードは多いがTypeScriptになるとあんまりなかったのでメモ

コード

export const groupBy = <T, K extends keyof any>(arr: T[], key: (i: T) => K) =>
  arr.reduce((groups, item) => {
    (groups[key(item)] ||= []).push(item);
    return groups;
  }, {} as Record<K, T[]>);

// 例
const list = [
  {
    "name": "taro",
    "role": "admin"
  },
  {
    "name": "jiro",
    "role": "staff"
  },
  {
    "name": "hanako",
    "role": "admin"
  }
];
console.log(groupBy(list, (x) => x.role));

見ればわかるが、第一引数は対象の配列、第二引数は何でグルーピングしたいかをアロー関数で指定する。

ネイティブで対応されるかも。。。?

かも?って疑問符なのはまだ全然実装まで遠そうだから。

developer.mozilla.org

まさに欲しい機能!って思ったがChromeにすら実装されてないので道のりは長そうだ。。

Javascriptでスネークケースをキャメルケース等に相互変換できるライブラリ「change-case」

やりたいこと

「test string」を「testString」に変換したり、「test_string」に変換したりと色々スネークケースやらキャメルケースを相互変換したい。

色々調べた結果、jsの場合はblakeembrey/change-caseのライブラリがよさげだった

インストール

npm install change-case

試してみる

import {pascalCase,paramCase } from "change-case";

console.log(paramCase('test string'));
//=> "test-string"

console.log(pascalCase('test string'));
//=> "TestString"

強い。自前でゴリゴリ書くぐらいならこっちのほうが信頼性高いわ

Typescript PlaywrightでinnerTextを取得する

環境

  • Playwright 1.25

やりたいこと

ページにある要素のinnerTextを取得したい

コード

ポイントは el: HTMLElement していること。これがないと型がanyになってしまいエラーになる。

import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch({});
  const page = await browser.newPage();

  const url = 'https://example.com/';
  await page.goto(url);
  await page.waitForSelector('h1');
  const code = await page.$eval('h1', (el: HTMLElement) => (el).innerText);
  console.log(code);
  await browser.close();
})();