You’ll ultimately need to use something like the the suggestion above, with “redundant” type parameters. You can use constructors (especially inner constructors) to perform the proper calculations and ensure valid combinations.
See recent discussion on Simple compile-time evaluation for struct types.
Here’s an example
struct C{T, S}
foo::S
function C(foo::T) where T
S = promote_type(Float32, T) # calculation to determine S
S <: Real || error("computed unusable type parameter S=$S") # validate S
return new{T, S}(convert(S, foo))
end
end