This code best describes it:
https://psalm.dev/r/f86eb62c76
/**
* @template A
*/
class Config {
/**
* @param (callable(): A)|null $x
*/
public function __construct($x = null)
{}
/**
* @template NewA
* @param (callable(): NewA)|null $x
* @return Config<NewA>
*/
public static function create($x = null)
{
return new self($x);
}
}
// Named constructor Tests:
/** @return Config<never>*/
function namedEmptyConfig() {
return Config::create();
}
/**
* This somehow resolves to mixed instead of never - even though the value is also null here:
* @return Config<never>
*/
function namedNullConfig() {
return Config::create(null);
}
// Test config constructor:
/**
* @return Config<never>
* Why does this work differently than the named constructor?
* I would expect "never" to be the result here, but instead it is mixed.
*/
function emptyConfig() {
return new Config();
}
/**
* @return Config<never>
* Same issue as in named constructor test - I'dd expect never here.
*/
function nullConfig() {
return new Config(null);
}
/** @return Config<string> */
function configured() {
return new Config(fn () => 'hello');
}
I noticed this error when wrapping in yet another layer which applies conditional love to this config.
Something along the lines of
@return ConfigA is empty ? Foo : Bar
It never resolves to Foo, since it is not empty.
If I change it to: ConfigA is mixed it always resolves to Foo
This code best describes it:
https://psalm.dev/r/f86eb62c76
I noticed this error when wrapping in yet another layer which applies conditional love to this config.
Something along the lines of
It never resolves to Foo, since it is not empty.
If I change it to:
ConfigA is mixedit always resolves to Foo