Skip to content

条件付き型

PsalmはTypeScriptの条件付き型に相当するものをサポートしています。

条件付き型は次の形式を取ります:

(<template param> is <union type> ? <union type> : <union type>)

すべての条件付き型は括弧で囲む必要があります。例:(...)

条件付き型はテンプレートパラメータに依存しているため、テンプレートパラメータが定義されている関数でのみ使用できます。

応用例

PHPの数値加算のユーザーランド実装を作りたいと仮定しましょう(ただし、実際にはこれを行わないでください)。これを条件付き戻り値型で型付けできます:

<?php
/** 
 * @template T of int|float
 * @param T $a
 * @param T $b
 * @return int|float
 * @psalm-return (T is int ? int : float)
 */
function add($a, $b) {
    return $a + $b;
}

add($x, $y) の結果を理解する際、Psalmはその特定の呼び出しについて T の値を推論しようとします。add(1, 2) を呼び出す場合、T は簡単に int と推論できます。次に、Psalmは提供された条件付き戻り値型 (T is int ? int : float) を取り、既知の T の値 int を代入します。その結果、式は (int is int ? int : float) となり、これは (true ? int : float) に簡略化され、さらに int に簡略化されます。

add(1, 2.1) を呼び出す場合、T は代わりに int|float と推論されます。これは式 (T is int ? int : float) が次のように置き換えられることを意味します: (int|float is int ? int : float) ユニオン int|float は明らかに int ではないので、式は (false ? int : float) に簡略化され、さらに float に簡略化されます。

ネストされた条件付き型

三項演算子と同様に、条件付き型をネストすることもできます:

<?php
class A {
    const TYPE_STRING = 0;
    const TYPE_INT = 1;

    /**
     * @template T of int
     * @param T $i
     * @psalm-return (
     *     T is self::TYPE_STRING
     *     ? string
     *     : (T is self::TYPE_INT ? int : bool)
     * )
     */
    public static function getDifferentType(int $i) {
        if ($i === self::TYPE_STRING) {
            return "hello";
        }
        if ($i === self::TYPE_INT) {
            return 5;
        }
        return true;
    }
}

ユーザーノート