とーますメモ

Ruby on Rails / Goなどの学習メモ

【GAS】claspで開発環境を作る

今回は既に既存プロジェクトがあり、その内容をコピーして環境を作成することを前提にする。

1. 準備

1-2. Node.jsのインストール

今回はVoltaを使用してNode.js環境を作った。

1-3. プロジェクト用ディレクトリの作成

project_path内直下ではgit系のファイルなどが入るため、project_path内で更にsrcディレクトリを作成し、純粋なソースコードはこの中で管理する。

$ mkdir [project_path] & cd [project_path]
$ mkdir src

2. clasp環境設定

以下のコマンドでclasp及びtypescirpt系のパッケージをインストールする

$ npm init -y
$ npm install @google/clasp -g
$ npm install @types/google-apps-script


以下のコマンドでclasp経由でプロジェクトへログインする

$ clasp login

ブラウザが開くので、認証すればOK

新規で作成する場合は、以下コマンドでプロジェクトを作成するが

$ clasp create

既存プロジェクトがある場合は、以下コマンドでプロジェクトをcloneする。

$ clasp clone [script-id]

cloneすると.clasp.jsonができるので、ファイル内のrootDirをsrcに向けた後、
.clasp.json以外のファイルを一回消せば、これ移行push/pullするときはsrcファイル内のデータを対象にしてpush/pullするようになるので便利

$ clasp pull
$ clasp push


[参考]
GAS のGoogle製CLIツール clasp - Qiita
claspを使ってGoogle Apps Scriptの開発環境を構築してみた | DevelopersIO

【Next.js】Apollo Queryの返り値を元に、新しいデータを非同期で取得する場合

ちょっとハマったので、自分のメモ用。

以下のissueにかかれていたことを元にして解決。
github.com

上記の内容をカスタムフックにラップすればOK

const { loading, data, error } = useQuery(SOME_QUERY)
const [state, setState] = React.useState([])

React.useEffect(() => {
  // do some checking here to ensure data exist
  if (data) {
    // mutate data if you need to
    setState(data)
  }
}, [data])

年月のみを入力した場合、その月の最終日を自動補完する方法

年月のみが入力されたときも、当月の最終日を自動補完するコードを作った。

ex) A1に年月または年月日が入力される前提

TEXT(IF(LEN(A1)=7, EOMONTH(A1, 0), C2:C), "YYMMDD")

2022/06 => 220630
2022/06/20 => 220620

ポイントはLEN関数の長さが7の場合で、年月判定している箇所。
他にも年月判定する方法があるかもしれないが、これでとりあえずは対応できる。

※ EOMONTHの第2引数を0にすると当月の最終日が取得できる

TypeScriptで簡易Sprintfを作成する

Validationメッセージなどのメッセージには決まった文言が入るが、一部を置き換えたい場合などは、テンプレートリテラルよりC言語系で使われるSprintfが便利なのだが、JavaScriptにないため自作した。

export const sprintf = (format: string, ...args: string[]): string => {
  return format.replace(/{(\d+)}/g, (_match, index) => {
    return args[index];
  });
};

sprintf('{0}を入力してください', '名前')
=> '名前を入力してください'

[参考]
javascript - Convert JS sprintf to Typescript equivalent - Stack Overflow
Is there a sprintf equivalent for node.js - Code Examples

React Hook Form v7 × Material UIを使用したときのメモ書き

React Hook Formを使用するのは初めて。
React Hook Formを使用することでform内の値を管理するstateが不要になり、バリデーション機能も含まれているため、コード量を大幅に減らすことができる。またネット上にサンプルも非常に多いのも魅力的。

form値の監視や、他のUIライブラリとも組み合わせるのも可能。

React Hook Form ファーストインプレッション

v7について

React Hook Formはv7では書き方が以前のバージョンとは違っている。
ちなみに公式の説明はこちら
Migrate From V6 to V7 | React Hook Form - Simple React forms validation

register関数の使い方
- <input ref={register({ required: true })} name="test" />
+ <input {...register('test', { required: true })} />

スプレッド構文を使用することでシンプルに記述できるようになった。
以下が影響が大きそうな部分。

Controller
- <Controller as={<input />} />
+ <Controller render={({ field }) => <input {...field} />}

- <Controller render={(props, meta) => <input {...props} />} />
+ <Controller render={({ field, fieldState }) => <input {...field} />} />

as属性は廃止になり、代わりにrender属性をv7からは使用する。
render属性はfieldとfieldStateを含むオブジェクトを返す。

errros
- const { errors } = useForm();
+ const { formState: { errors } } = useForm();

errorsオブジェクトはfromStateオブジェクト内に属することになった。

実装時に困ったこと

Select要素のラベル表示にすごく困った。
React Hook FormとMaterial UIを併せたSelectのサンプルを紹介しているサイトは結構あるけど、v7のやり方でやってる例が意外となく、Material UIのform独特なかっこいいラベルのUIが、うまく動作しないという問題が発生した。

結論から言うと、以下のサイトさんを参考にし
React 初心者が Material-UI で今どきの Web フォームを作ってみた(react-hook-form編) | DevelopersIO

Controller内にTextFieldを入れて、Textfieldにselect属性をつけることで
Material UIのあのかっこいいUI効果があるラベルが実装できた。

<Controller
  name="sample_select"
  control={control}
  defaultValue={"default value"}
  render={({ field }): JSX.Element => (
    <TextField {...field} fullWidth size="small" select label={"Sample Select"}>
      {options.map((v) => (
        <MenuItem key={v.name} value={v.id}>
          {v.name}
        </MenuItem>
      ))}
    </TextField>
  )}
/>


[参考]
Using Material UI with React Hook Form - LogRocket Blog

【React】Material UIについてのメモ書き

Material UI学習時のメモ書き

Gridシステム

bootstrapを使用するときも同じだが、まずは基本のGridシステムの使い方を最初に知る必要がある。

Gridは親Gridでcontainerを書き、その内側の子Gridでitemを定義する。
boostrapでいう、div class='container'とdiv class='row'と同じ関係。

<Grid container spacing={2}>>
  <Grid item xs={6} md={8}>
    <Item>xs=6 md=8</Item>
  </Grid>
  <Grid item xs={6} md={4}>
    <Item>xs=6 md=4</Item>
  </Grid>
  <Grid item xs={6} md={4}>
    <Item>xs=6 md=4</Item>
  </Grid>
  <Grid item xs={6} md={8}>
    <Item>xs=6 md=8</Item>
  </Grid>
</Grid>

レスポンシブデザインは、boostrapと同じように、breakpointがあり内容は以下。

xs, extra-small: 0px
sm, small: 600px
md, medium: 900px
lg, large: 1200px
xl, extra-large: 1536px

Breakpoints - Material UI
モバイルベースのxsベースで考えて、必要に応じてmdやlgを使う。

Auto-layoutという機能もあり、12の数値を全て、各rowに割り振るのではなく、
その一部に当てはめればあとは、使用可能ならスペースに応じて、均等に割り振ったwidthでレイアウトしてくれる。

<Grid container spacing={3}>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
  <Grid item xs={6}>
    <Item>xs=6</Item>
  </Grid>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
</Grid>

Grid container(親Grid)でよく使用する属性

direction

子Gridの並び順を定義できる。rowで横並び、columnで縦並び

<Grid container direction="row">
justifyContent

親Gridをメイン軸とし、子Gridを横軸のどの位置に配置するかを指定する
【CSS】justify-content使い方、アイテムの配置する位置を指定する | SHU BLOG

<Grid container justifyContent="flex-start"> // 先頭寄せ
<Grid container justifyContent="center"> // 中央寄せ
<Grid container justifyContent="flex-end"> // 末尾寄せ
alignItems

親Gridをメイン軸とし、子Gridを縦軸のどの位置に配置するかを指定する
【CSS】align-itemsの使い方、配置する方向を指定する! | SHU BLOG

<Grid container alignItems="flex-start"> // 上部寄せ
<Grid container alignItems="center"> // 中央寄せ
<Grid container alignItems="flex-end"> // 下部寄せ
spacing

子Grid間のスペースを設定できる。小数点を含めた正の数を指定できる。
またv5からspacingを含めた全てのproprsでレスポンシブ値をサポート

<Grid container spacing={{ xs: 2, md: 3 }} />
rowSpacingとcolumnSpacing

rowSpacing(縦)とcolumnSpacing(横)の間隔をサポート

<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
columns

デフォルトのカラム数である12を変更することができる。
細かいレイアウト表現が必要な時に便利そう。

<Grid container spacing={2} columns={16}>
  <Grid item xs={8}>
    <Item>xs=8</Item>
  </Grid>
  <Grid item xs={8}>
    <Item>xs=8</Item>
  </Grid>
</Grid>

sxを使ったスタイルの当て方

こんにちはMUI! 新しくなったMaterial UI v5

追記

V5でできるようになったこと。

こんにちはMUI! 新しくなったMaterial UI v5

TypeScript 4.5 ファーストインプレッション

個人用メモ。解釈が正しいかは不明なので参考までに。

TypeScript4.5がリリースされたので、その内容を簡単に試してみる。
devblogs.microsoft.com

TypeScriptを既にインストールしている場合は、以下で最新版に更新。

$ npm update typescript

初めてインストールする場合は以下。

$ npm install typescript

公式によるとTypeScript4.5の主な追加項目は以下。

The Awaited Type and Promise Improvements

The Awaited type can be helpful for modeling existing APIs, including JavaScript built-ins like Promise.all, Promise.race, etc. In fact, some of the problems around inference with Promise.all served as motivations for Awaited.

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#awaited-type

よくわからん。何が便利になるのかも不明。

=> PromiseLikeの説明
thenが実装しているPromise風オブジェクトのこと?

const fakePromise = { then: () => string };

async/await がやっていること - Qiita
JavaScriptの非同期処理をじっくり理解する (2) Promise

Supporting lib from node_modules

TypeScript does bundle certain libraries to ensure it works together well with Javascript. However, you might want to change those to another type of library implementation.

It is a similar behavior as of @types where you can now choose your appropriate type definitions.

https://betterprogramming.pub/whats-new-in-typescript-4-5-57d6b88b1e72

TypeScriptにバンドルされているライブラリの型定義ファイルを
指定することができるようになるため、適切な型定義ファイルを使用できるようになる?みたい。

TypeScript 4.5 変更点 まとめ

Template String Types as Discriminants

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#template-string-discriminants

以下のような、テンプレートリテラルの使い方ができるようになった。4.4以下では失敗する。

export interface Success {
    type: `${string}Success`;
    body: string;
}

export interface Error {
    type: `${string}Error`;
    message: string;
}

export function handler(r: Success | Error) {
    if (r.type === "HttpSuccess") {
        // 'r' has type 'Success'
        let token = r.body;
    }
}

--module es2022

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#module-es2022

TypeScriptでes2022モジュールをサポートできるようになった。
一番重要だと思われる機能は、awaitをasync関数外でも使用できるようになること。

Tail-Recursion Elimination on Conditional Types

Conditional Typesで型レベル末尾再帰最適化を行うらしい。

TypeScript 4.5 変更点 まとめ

よくわからん。飛ばす...

Disabling Import Elision

特定の条件下の元で、importしたモジュールを使用している場合、TypeScriptはそのモジュールを未定義と判断し削除するのを防ぐオプション。

以下のようなケースが想定される。

import { Animal } from "./animal.js";
eval("console.log(new Animal().isDangerous())");

Announcing TypeScript 4.5 - TypeScript

import { readFile } from "node:fs/promises";
eval(`readFile("./package.json", "utf-8").then(console.log);`);

TypeScript 4.5 変更点 まとめ

type Modifiers on Import Names

今まではtype修飾子をimport文で使用するときは、モジュールのimportととは分けて記述する必要があったが、4.5からは一緒にかけるようになった。

import type { FC } from 'react';
import { useEffect } from 'react';
import { type FC, useEffect } from 'react';

Private Field Presence Checks

プライベートプロパティの存在チェック。ユースケースがよくわからないが、
このチェックを使用することで、あるインスタンスが、どのクラスから生成されたかを証明することができるようになるということだと思う。
TypeScript 4.5 変更点 まとめ

Import Assertions

ランタイム実行時に、インポートする対象が想定したフォーマットになっているかチェックすることができる。この機能は、どうやらJSONなどのコードを実行する機能がないファイルをインポートする場合は、明示的にフォーマットを指定させることでセキュリティを向上させる狙いがあるっぽい。
GitHub - tc39/proposal-import-assertions: Proposal for syntax to import ES modules with assertions

Const Assertions and Default Type Arguments in JSDoc

一例として、as constを使用せずにJSDocのアサーションを使用することで同じ表現が可能になった?的なことかと。

Faster Load Time with realPathSync.native

内部的な話っぽいので、スキップ。

New Snippet Completions

補完機能が強化された模様。読む限り良さげな改善内容。
新しいVSCode上で動作するとのことだが、自分の環境では確認できず...

Better Editor Support for Unresolved Types

特定のケースにおいて、関数名をマウスオーバー時に表示されるコンテキスト情報が改善された模様。

Experimental Nightly-Only ECMAScript Module Support in Node.js

実験的な機能についての言及。よくわからない。


[参考資料]
TypeScript 4.5 変更点 まとめ
What’s New in TypeScript 4.5?. Awaited Type, type-only modifier… | by Jose Granja | Nov, 2021 | Better Programming