What do you call these? [array][string][int]

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:


[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.

Leave a Comment