Psalm Type Annotations Reference

July 1, 2026 · View on GitHub

Quick reference of all type annotations supported by Psalm 7. Useful when writing stubs and handlers.

Source of truth: vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeTokenizer.php (PSALM_RESERVED_WORDS) and vendor/vimeo/psalm/src/Psalm/DocComment.php (PSALM_ANNOTATIONS).

Psalm docs (deep links):

Scalar Types

TypeAtomicNotes
intTInt
floatTFloat
stringTString
boolTBool
trueTTrue
falseTFalse
nullTNull
voidTVoid
scalarTScalarint|float|string|bool
numericTNumericint|float|numeric-string
array-keyTArrayKeyint|string
mixedTMixedTop type
iterablearray|Traversable; accepts generics: iterable<TKey, TValue>
neverTNeverBottom type. Aliases: no-return, never-return, never-returns
objectTObjectAny object
resourceTResource
open-resourceTResourceActive resource
closed-resourceTClosedResourceClosed resource
boolean, integer, double, realDeprecated aliases

Integer Subtypes

TypeAtomicAdoptionNotes
positive-intTIntRangeWideint<1, max>
non-negative-intTIntRangeWideint<0, max>
negative-intTIntRangeRareint<min, -1>
non-positive-intTIntRangeRareint<min, 0>
literal-intTNonspecificLiteralIntNicheAn int known at analysis time
int<min, max>TIntRangeMediumRange. min = PHP_INT_MIN, max = PHP_INT_MAX
int-mask<1, 2, 4>TIntMaskNicheBitmask of listed values
int-mask-of<Foo::FLAG_*>TIntMaskOfNicheBitmask from class constants

String Subtypes

TypeAtomicAdoptionNotes
non-empty-stringTNonEmptyStringWide
non-falsy-stringTNonFalsyStringMediumNot empty and not '0'. Alias: truthy-string
numeric-stringTNumericStringWidePasses is_numeric()
literal-stringTNonspecificLiteralStringMediumComposed entirely of literals in source
non-empty-literal-stringTNonEmptyNonspecificLiteralStringNiche
lowercase-stringTLowercaseStringNichePsalm-only
non-empty-lowercase-stringTNonEmptyLowercaseStringNichePsalm-only
callable-stringTCallableStringMediumPasses is_callable()
class-stringTClassStringWideValid FQCN
class-string<Foo>TClassStringWideFQCN of Foo or subclass
interface-stringTClassStringNiche
trait-stringTTraitStringNiche
enum-stringTClassStringNiche

Literal Types

42              // literal int
3.14            // literal float
'hello'         // literal string
"hello"         // literal string
Foo::class      // literal class-string
Foo::CONST      // class constant value

Array / List Types

TypeAtomicNotes
arrayTArrayUntyped
array<TValue>TArrayShorthand for array<array-key, TValue>
array<TKey, TValue>TArray
non-empty-array<TKey, TValue>TNonEmptyArrayAt least one element
associative-arrayTArray
list<TValue>TKeyedArraySequential int-keyed array
non-empty-list<TValue>TKeyedArray
non-empty-countableCountable with at least one element

Array Shapes

array{key: string, id: int}        // required keys
array{key?: string}                // optional key
array{0: string, 1: int, ...}     // known prefix + open-ended
list{string, int, float}          // positional list shape

Object Shapes

object{foo: string, bar: int}
object{foo?: string}               // optional property

Callable Types

TypeAtomicAdoptionNotes
callableTCallableWide
ClosureTClosureWide
callable(int, string): boolTCallableWideTyped callable
Closure(int, string): boolTClosureWideTyped closure
callable(int, string=): voidTCallableMedium= marks optional param
callable(int, string...): voidTCallableMedium... marks variadic param
callable-stringTCallableStringMediumString that is callable
callable-arrayTKeyedArrayNicheArray that is callable
callable-listTKeyedArrayNicheList that is callable
callable-objectTCallableObjectNicheObject with __invoke
stringable-objectTNamedObjectNicheObject with __toString

Callable Mutation Modifiers

TypeAdoptionNotes
pure-callable / pure-ClosureNicheNo side effects
impure-callable / impure-ClosureRareDefault behavior, explicit
self-accessing-callable / self-accessing-ClosureRareReads $this properties
self-mutating-callable / self-mutating-ClosureRareReads and writes $this

Generics

/** @template T */
/** @template T of SomeType */           // upper bound
/** @template-covariant T */
/** @extends Base<int, string> */
/** @implements Interface<Foo> */
/** @use TraitName<Bar> */

Utility Types

TypeAtomicAdoptionNotes
key-of<T>TKeyOfMediumArray key type
value-of<T>TValueOfMediumArray value type
properties-of<T>TPropertiesOfNicheAll properties as keyed array
public-properties-of<T>TPropertiesOfNichePsalm-only
protected-properties-of<T>TPropertiesOfNichePsalm-only
private-properties-of<T>TPropertiesOfNichePsalm-only
class-string-map<T of Foo, T>TClassStringMapNicheMaps class-strings to instances
T[K]TTemplateIndexedAccessNicheIndexed access on template types
arraylike-objectTNamedObjectRareObject usable as array

Conditional Types

Syntax: (condition ? TypeIfTrue : TypeIfFalse). Conditions can test is, type narrowing on params, or even func_num_args().

// Basic: narrow return type based on a template param
/** @return (T is string ? int : float) */

// Nullable input → nullable output
/** @return ($path is null ? null : string) */

// Return type depends on a boolean flag
/** @return ($choose is true ? TA : TB) */

// Non-empty guard
/** @return ($format is non-empty-string ? non-empty-string : string) */

// Lowercase propagation
/** @return ($lowercase is true ? lowercase-string : string) */

// Null-or-value pattern (common in Laravel)
/** @return ($location is null ? int : int|null) */

// Ternary with union fallback
/** @return ($return is true ? string : void) */
/** @return ($return is true ? string : true) */
/** @return ($return is true ? string : bool) */

// Array emptiness drives return type
/** @return (TArray is non-empty-array ? non-empty-list<key-of<TArray>> : list<key-of<TArray>>) */
/** @return (TArray is array<never, never> ? null : TValue) */
/** @return (TArray is array<never, never> ? false : TValue|false) */

// Nested conditionals
/**
 * @return ($num is int ? positive-int|0 : ($num is float ? float : positive-int|0|float))
 */

// Overload based on argument count
/** @return (func_num_args() is 2 ? (null|list<float|int|string|null>) : int) */
/** @return (func_num_args() is 0 ? array<string, string> : string|false) */

Union and Intersection

int|string              // union
?string                 // shorthand for string|null
Foo&Bar                 // intersection (must satisfy both)

Type Aliases

/** @psalm-type UserId = positive-int */
/** @psalm-import-type UserId from UserService */

Docblock Annotations

Standard PHPDoc (Psalm-aware)

@var, @param, @return, @property, @property-read, @property-write, @method, @throws, @deprecated, @internal, @mixin

The type-carrying tags (@var, @param, @return, @property*, @method) also accept a @psalm- prefix (e.g. @psalm-param) for advanced type syntax that phpDocumentor can't parse. PHPStan prefix (@phpstan-param, etc.) is also recognized. @psalm-throws, @psalm-deprecated, and @psalm-mixin do NOT exist — Psalm rejects unknown @psalm-* tags with Unrecognised annotation (see DocComment::PSALM_ANNOTATIONS).

Assertions

AnnotationWhen it applies
@psalm-assert Type $paramFunction returns normally
@psalm-assert !Type $paramFunction returns normally
@psalm-assert-if-true Type $paramFunction returns true
@psalm-assert-if-true !Type $paramFunction returns true
@psalm-assert-if-false Type $paramFunction returns false
@psalm-assert-if-false !Type $paramFunction returns false
@psalm-assert-untainted $paramFunction returns normally (taint analysis: marks param untainted)

Negated assertions (!Type) assert the param is not of the given type. Common examples: !null, !false, !string.

Output Type Narrowing

AnnotationNotes
@psalm-param-out Type $paramBy-ref param type after call
@psalm-self-out Type$this type changes after call
@psalm-this-out TypeSame as self-out
@psalm-if-this-is TypePrecondition on $this type

Suppression and Debugging

AnnotationNotes
@psalm-suppress IssueTypeSuppress a specific issue
@psalm-tracePrint inferred type (debug)
@psalm-check-typeAssert inferred type matches
@psalm-check-type-exactAssert exact type match
@psalm-ignore-varIgnore @var in same docblock
@psalm-ignore-nullable-returnSuppress nullable return issues
@psalm-ignore-falsable-returnSuppress false return issues
@psalm-ignore-variable-methodIgnore variable method in dead code
@psalm-ignore-variable-propertyIgnore variable property in dead code

Purity and Mutability

AnnotationScope
@psalm-pureFunction: output depends only on input
@psalm-impureExplicitly marks side effects
@psalm-mutation-freeMethod: no mutation of any state
@psalm-external-mutation-freeMethod: may mutate $this, nothing external
@psalm-immutableClass: all properties readonly, all methods mutation-free
@psalm-mutableClass: explicitly not immutable (default)

Readonly

AnnotationNotes
@psalm-readonly / @readonlyProperty only writable in constructor
@psalm-allow-private-mutationReadonly but writable in private methods
@psalm-readonly-allow-private-mutationShorthand for both

Sealing

AnnotationNotes
@psalm-seal-propertiesNo undeclared __get/__set access
@psalm-seal-methodsNo undeclared __call access
@psalm-no-seal-propertiesReverse seal
@psalm-no-seal-methodsReverse seal

Visibility Overrides

AnnotationNotes
@psalm-override-property-visibilityOverride property visibility
@psalm-override-method-visibilityOverride method visibility

Class-Level

AnnotationNotes
@psalm-consistent-constructorAll child constructors match signature
@psalm-consistent-templatesTemplate params stay consistent in children
@psalm-inheritorsRestrict which classes can extend
@psalm-require-extends ClassNameTrait only usable in subclasses of ClassName
@psalm-require-implements InterfaceTrait only usable in implementors
@psalm-api / @apiMark as used (suppress unused code detection)
@psalm-internal NamespaceRestrict usage to a namespace

Generators and Scope

AnnotationNotes
@psalm-yield TValueOn a class/interface: declares what type a generator receives when yielding this object. Used for Promise/Deferred patterns -- TValue must be a @template param. Psalm resolves it via template expansion
@psalm-variadicOn a function: marks it as accepting unlimited arguments even without ... in the signature. Useful for functions that rely on func_get_args() internally
@psalm-scope-this TypeOn a statement block: overrides the type of $this for the enclosed code. Useful for closures bound to other objects at runtime (e.g. Closure::bind(), Laravel macros)

Stub-Specific

AnnotationNotes
@psalm-stub-overrideSafety guard for stubs: asserts that the annotated class/method exists in the original codebase. Psalm throws an error if no original counterpart is found, catching typos and stale stubs early

Other

AnnotationNotes
@no-named-argumentsDisallow named arguments on this function

Taint Analysis Annotations

AnnotationNotes
@psalm-taint-source TaintTypeMark return as taint source (e.g. html, sql, shell)
@psalm-taint-sink TaintType $paramMark param as taint sink
@psalm-taint-escape TaintTypeMark return as escaped/sanitized
@psalm-taint-unescape TaintTypeMark return as unescaped
@psalm-taint-specializeTrack taint per-instance or per-call
@psalm-flow ($param) -> returnDefine explicit taint flow path

Taint kinds: html, has_quotes, sql, shell, file, cookie, header, ldap, ssrf, xpath, sleep, extract, user_secret, system_secret, callable, eval, unserialize, include, llm_prompt, plus the aliases input / tainted / input_except_sleep — see Psalm\Type\TaintKind::TAINT_NAMES. Arbitrary custom kind names are also accepted (they report as TaintedCustom). Full table with attack vectors: Taint Analysis.