psalm icon indicating copy to clipboard operation
psalm copied to clipboard

Merging object-like arrays on imported type does not work

Open mstilkerich opened this issue 2 years ago • 6 comments

Using intersection types, it is possible to extend array shapes as described here.

This works fine:

<?php

/**
 * @psalm-type SaveData = array{name: string}
 * @psalm-type ExtSaveData = SaveData & array{id:string}
 */
Class Test1 {
}

However, if I want to do the same when one of the types is imported from another file, I get an error from psalm:

/********** FILE Test1.php **********/
<?php

/**
 * @psalm-type SaveData = array{name: string}
 */
Class Test1 {
}

/********** FILE Test2.php **********/
<?php

/**
 * @psalm-import-type SaveData from Test1
 * @psalm-type ExtSaveData = SaveData & array{id:string}
 */
Class Test2 {
}

This will produce the following error:

ERROR: InvalidDocblock - Test2.php:8:1 - Intersection types must be all objects, Psalm\Type\Atomic\TKeyedArray provided (see https://psalm.dev/008)
/**
 * @psalm-import-type SaveData from Test1
 * @psalm-type ExtSaveData = SaveData & array{id:string}
 */
Class Test2 {

mstilkerich avatar Dec 22 '22 13:12 mstilkerich

I have encountered this as well :(

jack-worman avatar Dec 22 '22 14:12 jack-worman

Looks like this is the same as https://github.com/vimeo/psalm/issues/9603 - see (temporary) "as" fix on that issue

kkmuffme avatar May 29 '23 13:05 kkmuffme

Another very similar example: https://psalm.dev/r/82a8ee14d5

asgrim avatar Oct 17 '23 12:10 asgrim

I found these snippets:

https://psalm.dev/r/82a8ee14d5
<?php

namespace A {
  /**
   * @psalm-type AType = array{test: string}
   */
  class AAA {
  }
}

namespace B {
  /**
   * @psalm-import-type AType from \A\AAA
   * @psalm-type BType = array{anotherTest: string}
   * @psalm-type Compound = AType&BType
   */
  class BBB {
    /**
     * @param Compound $type
     */
    public function useCompoundType($type): void
    {
       /** @psalm-trace $type */
       return;
    }
  }
}
Psalm output (using commit 67d6468):

ERROR: InvalidDocblock - 17:3 - The intersection type must not mix array and object types!

ERROR: UndefinedDocblockClass - 19:15 - Docblock-defined class, interface or enum named B\Compound does not exist

psalm-github-bot[bot] avatar Oct 17 '23 12:10 psalm-github-bot[bot]

Another one, with minimalistic annotation. https://psalm.dev/r/bce2b8edcb

discordier avatar Apr 17 '24 13:04 discordier

I found these snippets:

https://psalm.dev/r/bce2b8edcb
<?php

/**
 * @psalm-type TBaseConfiguration=array{type?: string, ...<string, mixed>}
 * @psalm-type TConfiguration=array{name: string}&TBaseConfiguration
 */
class Working2 {}

/** @psalm-type TBaseConfiguration=array{type?: string, ...<string, mixed>} */
class BaseClass {}

/**
 * @psalm-import-type TBaseConfiguration from BaseClass
 * @psalm-type TConfiguration=array{name: string}&TBaseConfiguration
 */
class BrokenDueToImportedType1 {}
Psalm output (using commit 08afc45):

ERROR: InvalidDocblock - 16:1 - Intersection types must be all objects or all keyed array.

psalm-github-bot[bot] avatar Apr 17 '24 13:04 psalm-github-bot[bot]