psalm icon indicating copy to clipboard operation
psalm copied to clipboard

Use a parameter value as part of an assert's type?

Open ciaranmcnulty opened this issue 2 years ago • 1 comments

I guess this is something like generics but I can't quite get my head around it

I want to write an assertion function (possibly to contribute back to a library) that checks an array has specific keys ONLY but am not sure how I can possibly annotate it?

Is there a way to tell psalm that the shape of the array is dictated by the param to the assertion?

https://psalm.dev/r/1f919a9f94

ciaranmcnulty avatar Jan 09 '23 12:01 ciaranmcnulty

I found these snippets:

https://psalm.dev/r/1f919a9f94
<?php

/**
 * @param list<array-key> $expected
 * 
 * what can I psalm-assert here?
 */
function assertArrayKeys(array $expected, array $input): void
{
    // real impl will be more complex of course
    
    $actual = array_keys($input);
    
    sort($expected);
    sort($actual);
    
    assert($expected === $actual);
}

/**
 * @param array{foo: mixed, ...} $f
 * @return array{foo: mixed}
 */
function receive(array $f) {
    assertArrayKeys(['foo'], $f);
    return $f;   
}
Psalm output (using commit 729c0ba):

ERROR: InvalidReturnStatement - 26:12 - The inferred type 'array{foo: mixed, ...<array-key, mixed>}' does not match the declared return type 'array{foo: mixed}' for receive

ERROR: InvalidReturnType - 22:12 - The declared return type 'array{foo: mixed}' for receive is incorrect, got 'array{foo: mixed, ...<array-key, mixed>}'

psalm-github-bot[bot] avatar Jan 09 '23 12:01 psalm-github-bot[bot]