Don Cruickshank’s helpful answer provides one piece of the puzzle, but let me try give a comprehensive overview:
By itself, a [<fullTypeNameOrTypeAccelerator>]
expression is a type literal, i.e. a reference to a .NET type in the form of a System.Reflection.TypeInfo
instance, which is rich source of reflection on the type it represents.
<fullTypeNameOrTypeAccelerator>
can be the full name of a .NET type (e.g., [System.Text.RegularExpressions.Regex]
– optionally with the System.
prefix omitted ([Text.RegularExpressions.Regex]
) or the name of a PowerShell type accelerator (e.g, [regex]
)
Type literals by themselves are used:
-
Typically, to access static members (typically methods) via
::
, the static member-access operator; e.g.:# Call the static 'Match' method of the [regex] # (System.Text.RegularExpressions.Regex) type. # -> '10' [regex]::Match('A10', '\d+').Value
-
Less frequently, to reflect on the given type by calling the instance methods of the
TypeInfo
instance that every type literal is; e.g.:# Get the names of all .NET interfaces that the [regex] # (System.Text.RegularExpressions.Regex) implements. # -> 'ISerializable' [regex].GetInterfaces().Name
Type literals are also used in the following constructs:
-
As casts, to convert (coerce) the (RHS[1]) operand to the specified type or to construct an instance, if possible:
# Convert a string to [datetime] (System.DateTime). # Equivalent to the following call: # [datetime]::Parse('1970-01-01', [cultureinfo]::InvariantCulture) [datetime] '1970-01-01' # Construct a [regex] instance. # The same as the following constructor call: # [regex]::new('\d+') $re = [regex] '\d+'
- The examples show that PowerShell casts are much more flexible than in C#, for instance, and instance construction and type conversions frequently happen implicitly – see this answer for more information. The same rules apply to all the other uses listed below.
-
As type constraints:
-
To specify the type of a parameter variable in a function or script:
function foo { param([datetime] $d) $d.Year }; foo '1970-01-01'
-
To lock in the type of a regular variable for all future assignments:[2]
[datetime] $foo = '1970-01-01' # ... $foo = '2021-01-01' # the string is now implicitly forced to [datetime]
-
-
As the RHS of the
-is
and-as
operators, for type tests and conditional conversions:-
-is
tests not only for the exact type, but also for derived types as well as interface implementations:# Exact type match (the `Get-Date` cmdlet outputs instances of [datetime]) (Get-Date) -is [datetime] # $true # Match via a *derived* type: # `Get-Item /` outputs an instance of type [System.IO.DirectoryInfo], # which derives from [System.IO.FileSystemInfo] (Get-Item /) -is [System.IO.FileSystemInfo] # $true # Match via an *interface* implementation: # Arrays implement the [System.Collections.IEnumerable] interface. 1..3 -is [System.Collections.IEnumerable] # true
-
-as
converts the LHS instance to an instance of the RHS type if possible, and returns$null
otherwise:'42' -as [int] # 42 'foo' -as [int] # $null
-
-
[PowerShell v7.3+ only] As the type arguments in generic method calls:
-
E.g, the following calls the
Enumerable.OfType<TResult>(IEnumerable)
LINQ method with[int]
as its type argument (thereby requesting that only enumerable elements that are of that type be returned):# -> 2, 4 [System.Linq.Enumerable]::OfType[int](@('one', 2, 'three', 4))
-
[1] In the context of operators and mathematical equations, the initialisms LHS and RHS are commonly used, referring to the left-hand side and right-hand side operands, respectively.
[2] Technically, there is no real difference between a parameter and a regular variable: the type constraints functions the same way in both cases, but parameter variables, after having been bound (assigned to) automatically on invocation, aren’t usually assigned to again.