Some unexplained example in defining concrete type from an abstract type with multiple parameters

Suppose I have a base type, which is abstract:
SuperType{T, S, T} = Tuple{T, S, T} where T <: Real where S <: AbstractString

Indeed SuperType can be used for type assertion successfully:

(1.0, "hello", 1.0)::SuperType #> OK
(1.0, "hello", 1)::SuperType #> Error

Now I try to define a concrete type as a subtype of Supertype:
SubType = SuperType{Int, String, Int}

But it fails:

TypeError: in Type, in S, expected S<:AbstractString, got Type{Int64}

I suspect this is somehow related to what are the innermost parameters and what are the outermost
because of the following results:

Following is OK

Tuple2{S,T} = Tuple{S,T} where T<:Real where S<:String 
Tuple2{String, Int}

But following produces TypeError: in Type, in T, expected T<:Real, got Type{String}

Tuple3{S,T} = Tuple{S,T} where S<:String  where T<:Real 
Tuple3{String, Int}

I wonder what principle can explain all these behaviors coherently and how I define SubType as intended. It would be great if the document adds this corner case to improve understanding.

I 've just realized what mistake I made. There are only two type variables T and S but I specified three in defining a concrete subtype. Also, although not explicitly stated in the document, it is evident by experiment that the innermost type variable should come first. So the correct way is

SubType = SuperType{String, Int}

1 Like