お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
言語::TypeScriptジャンル::調査

TypeScriptをぼちぼちやってきた中で、型推論が素直に決まらないみたいな所が出てきたので書き置きとして残しておきます
具体的には何かしらの関数を通して処理を隠蔽すると上手くいかなくなるケースがあります

型が推論されないケース

検査関数的なものを通した場合に、後続処理で期待通り型が推論されなくなるケースです

その1

type HogePiyo = 'hoge' | 'piyo';

type InputProps<ValueT> = {
  value: ValueT;
  error: string;
};

const required = (val: string) => {
  return val === '';
};

const registerHogePiyo = (value: HogePiyo) => {
  console.log('register', value);
};

const input: InputProps<HogePiyo | ''> = {
  value: '',
  error: '',
};

if (required(input.value)) {
  input.error = 'ERR';
  console.error(input.error);
} else {
  // ここでは input.value は 'hoge' | 'piyo' となるはずだが
  // TSC は 'hoge' | 'piyo' | '' と解釈する
  registerHogePiyo(input.value);
}

その 2

type HogePiyo = 'hoge' | 'piyo';

type InputProps<ValueT> = {
  value: ValueT;
  error: string;
  hasError: boolean;
};

const required = <ValueT>(obj: InputProps<ValueT | ''>) => {
  if (obj.value === '') {
    return { value: '', error: '必須入力です', hasError: true };
  } else {
    return { value: obj.value, error: '', hasError: false };
  }
};

const registerHogePiyo = (value: HogePiyo) => {
  console.log('register', value);
};

const input: InputProps<HogePiyo | ''> = {
  value: '',
  error: '',
  hasError: false,
};

const result = required(input);
if (result.hasError) {
  console.error(result.error);
} else {
  // ここでは input.value は 'hoge' | 'piyo' となるはずだが
  // TSC は 'hoge' | 'piyo' | '' と解釈する
  registerHogePiyo(result.value);
}

export {};

型を推論されるようにしたケース

オブジェクトに型判定用のプロパティを生やしasで型を明示することでクリアしています

type HogePiyo = 'hoge' | 'piyo';

type InputProps<ValueT> = {
  value: ValueT;
  error: string;
  hasError: boolean;
};

const required = <ValueT>(obj: InputProps<ValueT | ''>) => {
  if (obj.value === '') {
    return { value: '', error: '必須入力です', hasError: true } as {
      value: '';
      error: string;
      hasError: true;
    };
  } else {
    return { value: obj.value, error: '', hasError: false } as {
      value: ValueT;
      error: string;
      hasError: false;
    };
  }
};

const registerHogePiyo = (value: HogePiyo) => {
  console.log('register', value);
};

const input: InputProps<HogePiyo | ''> = {
  value: '',
  error: '',
  hasError: false,
};

const result = required(input);
if (result.hasError) {
  console.error(input.error);
} else {
  registerHogePiyo(result.value);
}

export {};

あとがき

  • Assertion Functionsを使う方法もあると思いますが、何も考えずAssertion Functionsを書くと次のような弊害があり、積極的に採用しづらいと考えています
    • 何もしていなければ基本的にバンドル後のソースコードに出てくる
      • 要するにバンドルサイズが大きくなります
    • throwを書く必要性があり、バンドル後に残っている以上、このthrowcatchする必要性がある
      • 無意味な実装工数が生まれる
    • そもそも論としてAssertion Functionsを書く工数が生まれる
    • Assertion Functionsの振る舞いを見ている限り、asに限りなく近く、ぶっちゃけasで書いたほうが楽
  • 絶対にasを使わず現実的な工数で開発するというのは、割と非現実ではないかという感触があります
    • 個人的に型推論はIDEが勝手にやってくれるおかげで楽ができるシステムだと考えているので、型推論の補佐をする仕組みに工数をかけるというのは本末転倒な気がしています
  • 品質は大切なことですが、反面で少なくないビジネスには期限もあります
    • 品質に寄せすぎた過剰に冗長なコードも、納期に寄せすぎた脆弱性不具合山盛りスパゲティコードもどちらも考えものであり、その辺のバランスが上手くとれるやり方がなんかないかなーと考えることはしばしばあります
投稿日:
言語::PHP::XdebugOS::Windowsソフトウェア::VSCode

環境

Windows 10

Env Ver
PHP 8.0.2
Xdebug 3.0.2

php.ini

zend_extension="xdebug-3.0.2-8.0-vs16-nts-x86_64"
xdebug.start_with_request=yes
xdebug.mode=debug

settings.json

別になくてもデバッグは出来る

"php.validate.executablePath": "C:/path/to/php.exe",

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        }
    ]
}
投稿日:
言語::PHP
$arr = ['a', 'b', 'c'];
$test1 = '';
$test2 = '';
$test3 = '';
for($idx = 0; count($arr) > $idx; $idx++) {
	${'test' . ($idx + 1)} = $arr[$idx];
	// $this->{'test' . ($idx + 1)} = $arr[$idx];とするとクラスのプロパティも行ける
}
// $test1 = 'a'
// $test2 = 'b'
// $test3 = 'c'
投稿日:
OS::Linux::コマンド言語::Perl

文字列を編集したりするのに大変便利なやつ。sedやawkの代わりに使える。構文はPerlそのものが使える。なにせPerlなので

コマンドラインオプション

  • -e
    • ワンライナーでコードを書くやつ
    • php -rnode -eと同じ
    • Evaluate, Eval, 評価
  • -n
    • 入力の各行に対し処理がかかる
    • $.で行番号、$_で行の文字列を取得できる
    • while (<>)相当の処理
  • -p
    • 入力の各行に対し処理を行い、更にprint $_相当の処理を実行する
  • -l
    • 入力($_)から改行文字を削除し出力に改行を追加する
  • -a
    • 入力の各行に対してawk相当の文字列分割処理を行う(autosplit mode with -n or -p)
    • 分割した文字は$Fに配列として入るので次のようにして取得できる
      • perl -ale 'print "$F[0] - $F[1]'
    • $#Fを指定すると分割した個数が取れる
  • -F/pattern/
    • -aでsplitするパターンを設定する
    • 例えば-F,とするとCSVを分割できる
  • -i[ext]
    • ファイルを編集する
    • 使用例:perl -i -pe 's/aaa/xxx/' foo.txt
    • -i.bakのように指定するとバックアップファイルが作成される
    • このオプションは次に続く文字が解釈されるため、単体で指定する必要がある(-ipeのようには使えない)

構文

変数を指定しない場合、基本的に$_として扱われる

  • print
    • 標準出力に出力
    • 単体ではprint $_と同じ挙動をする
  • $hoge =~ s/foo/bar/
    • fooをbarに置換
  • /(.+)/; print $1
    • キャプチャした内容を出力
    • コマンド例:echo hoge.jpg | perl -ne '/(.+)./; print $1'
  • $_
    • 基本的に書かなくても補完される
    • 例えばecho aaabbc | perl -ne 's/c/d/; print'の出力はaaabbdとなる
    • その他特殊変数:https://perldoc.jp/docs/perl/5.18.1/perlvar.pod
  • END{}
    • このブロックで囲んだコードは実行時の最後に動作する
      • -n, -pを指定した場合、END{}$_が取れないので渡す場合は$x = $_; END{ print $x }のように別の変数に代入する必要がある
    • https://perldoc.jp/docs/perl/5.38.0/perlmod.pod#BEGIN44-32UNITCHECK44-32CHECK44-32INIT32and32END

チートシート

変数置換

一例

ls -l | perl -ale '$F[8] =~ s/\.html//; print "$F[8]";'

特定行を取得

1のところが行数なので、ここを変えることで任意の行の文字列を取れる

perl -ne 'print if $. == 1'

正規表現の名前付きキャプチャ

echo "foo bar" | perl -pe 's/(?<first>.+) (?<last>.+)/$+{first}-$+{last}/'

逆順出力

unshiftで配列の先頭に値を追加し、END{}で最後に出力している

cat <<EOF | perl -ne 'unshift @x, $_; END{ print @x }'
aaa
bbb
ccc
EOF

確認環境

Env Ver
next 11.1.2
typescript 4.3.4

サンプルコード

__mocks__/next/router.ts

export const useRouter = () => {
  return {
    route: '/',
    pathname: '',
    query: '',
    asPath: '',
    push: jest.fn(),
    replace: jest.fn(),
    events: {
      on: jest.fn(),
      off: jest.fn(),
    },
    beforePopState: jest.fn(() => null),
    prefetch: jest.fn(() => null),
  };
};