2022年 12月 の投稿一覧

seeders のサブディレクトリ内に配置したSeeder クラスを、artisan CLI から実行したい:–class にname space を指定する

皆さまこんにちは、ウチイダです。

LaravelのSeederが便利でよく使っています。

テスト用のレコードを生成する処理をまとめておくと、いろいろ使いまわしがしやすいです。

でも、困るのがファイル数が増えてきたときの取り扱いです。database/seeders ディレクトリに全部入れてしまうと、ファイルを探しづらくなってしまいます。

というわけで、Seederクラスをサブディレクトリに分けることにしました。

検証環境

  • Laravel v9.43.0
  • PHP v8.1.13
  • Windows11 21H2

サブディレクトリにSeeder クラスファイルを作る

artisan で生成するときに、サブディレクトリを含めて指定するだけでOKです。

$ sail artisan make:seed Subfolder/SampleSeeder

   INFO  Seeder [database/seeders/Subfolder/SampleSeeder.php] created successfully.  

database/seeders/Subfolder 配下に、Seeder クラスを作ってくれました。

artisan コマンドから、サブディレクトリのSeeder を直接呼び出す

ここからが本題です。artisan db:seed は、–class に実行するSeeder クラス名を指定することができます。

これを使って、サブディレクトリにあるSeeder を呼び出します。

ちょっとだけ修正して、テキストだけ表示するように変更します。

<?php

namespace Database\Seeders\Subfolder;

use Illuminate\Database\Seeder;

class SampleSeeder extends Seeder
{
    public function run()
    {
        echo "サブフォルダのSeeder だよ~\n";
    }
}

それでは、いざ実行!

# name space を記述しないとエラー
$ sail artisan db:seed --class='SampleSeeder'

   INFO  Seeding database.  


   Illuminate\Contracts\Container\BindingResolutionException 

  Target class [Database\Seeders\SampleSeeder] does not exist.

クラスの名前解決ができません。クラス名だけ書くと、Database/Seeders 内を探すようになっているようです。

では追加の名前空間を指定すると…?

# Seeders 以降のname space を記述してもエラー
$ sail artisan db:seed --class='Subfolder\SampleSeeder'

   INFO  Seeding database.  


   Illuminate\Contracts\Container\BindingResolutionException 

  Target class [Subfolder\SampleSeeder] does not exist.

これでもエラーです。

名前空間を指定する(–class に \ を含む文字列を渡す)と、Database/Seeders は使わなくなってしまいました。

仕方ないので、全部指定します。

# name space を全部書くと名前解決できる
$ sail artisan db:seed --class='Database\Seeders\Subfolder\SampleSeeder'

   INFO  Seeding database.  

サブフォルダのSeeder だよ~

今度は実行できています。これは面倒…!

少し調べてみたところ、composer.json のautoload の設定を変えることで対応するやり方がいくつか見つかりました。

しかし、更新日付が古く、おそらくLaravel5 か 6 のころの話だと思われます。

また、クラス名の解決の仕方はdb:seed の挙動なので、autoload の設定でどうにかなるものではないような気がしています。

とりあえずname space を全部書くか、artisan CLI からの直接実行はあきらめるか、のどちらかになりそうです。

以上です。あなたのお役に立てればうれしいです。

React TypeScript で flexWrap、flexDireciton がエラー: CSSProperties を指定して回避

皆さまこんにちは、ウチイダです。

表題の件でエラーに遭遇したので、対策をメモしておきます。

環境

  • React 18.2.0
  • Typescript 4.9.3
  • @types/React 18.0.26
  • Vite 3.2.5

事象

CSS in JS でスタイルを記述した際、flexWrapを含んだオブジェクトを変数に格納してから、style 属性に渡すとエラーが出ます。

style 属性にそのままオブジェクトを書いた場合はエラーになりません。

export const FlexStyleError = () => {
	const elementStyle = {
		flexWrap: 'wrap'
	};

	return (
		<>
			<div style={{ flexWrap: 'wrap' }}>これはセーフ</div>
			<div style={elementStyle}>オブジェクトで渡すとエラー</div>
		</>
	)
}

エラーメッセージはこんな感じ。flexWrapの値として、string 型は渡せないよ~と言われてます。

Type '{ flexWrap: string; }' is not assignable to type 'Properties<string | number, string & {}>'.
  Types of property 'flexWrap' are incompatible.
    Type 'string' is not assignable to type 'FlexWrap | undefined'.ts(2322)
index.d.ts(1869, 9): The expected type comes from property 'style' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'

ちなみに、flexDirection でも同じエラーが起こります。

原因:csstype の型定義が使えてないから?

flexWrap とflexDirection には、それぞれFlexWrap と FlexDirection という専用の型があります。

  export type FlexWrap = Globals | "nowrap" | "wrap" | "wrap-reverse";

指定の文字列リテラルのUnion型として定義されていて、オブジェクトに渡した内容が正しく型を認識できてないぽいです。

解決方法:推論に任せず指定する

原因は分かったけど、よい解決策がわかりません。

というわけでエラーメッセージで検索したら、GitHubでissue が立っていました。

flexDirection is not assignable to CSSProperties 

まさにこれだ~と思いながらレスを追っていくと、いくつか対策が書かれていました。

要するに、型推論がちゃんとされなくてエラーになっちゃってるので、明確に指定すれば大丈夫ということです。

個人的には、styleに渡すオブジェクト全体に、React.CSSProperties を指定するのがいいかなと思いました。

flexDirection 以外のプロパティで問題が出ても、対処できそうです。

export const FlexStyleError = () => {
	// const elementStyle = {
	// React.CSSProperties 型を指定
	const elementStyle: React.CSSProperties = {
		flexWrap: 'wrap'
	};

	return (
		<>
			<div style={{ flexWrap: 'wrap' }}>これはセーフ</div>
			<div style={elementStyle}>オブジェクトで渡すとエラー</div>
		</>
	)
}

エラーも出なくなったし、そのうえ、プロパティのヒントも出してくれるように!

ReactCSSProperties を型指定することで、ヒントが正確に出る

CSS in JS を使うときは、型指定するとよい感じにプロパティが書けそうです。

以上です。

あなたのお役に立てればうれしいです。