Hi there, thank you for the report! The reason for this is a bit subtle, but effectively, today, Instance.new
is given the type (string, ...any) -> any
as a baseline, and the type system as embedded in Roblox implements a magic function that understands the relationship between the string being passed to Instance.new
when it is a literal and the actual type system. When it is not a literal, the magic function cannot trigger, and you just get any
as the result type. As such, in your function case, where you’re taking an arbitrary string as the parameter, you’re always returning something of type any
from Instance.new
and so no error is reported.
In the old Type Solver, we did not really have any possibility of making the type for Instance.new
more accurate than this because the “real” type in some kind of abstract sense is what’s called a dependent type (one of the most powerful and expressive type system features, and one that is not in any language you’re likely to have heard of before). In kind of made up syntax, it’s really something like: (instanceName: string) -> reify<instanceName>
where, somehow, reify<instanceName>
turns the runtime value of that argument into an appropriate type. Since the old Type Solver is not expressive enough to support this, we made a decision, as an affordance to users, to type it as any
since the alternative would likely mean giving it the type Instance
and requiring lots of downcasts. So, in a direct sense, this behavior is expected today and a conscious decision about the signature of Instance.new
.
In the New Type Solver, it is now possible, albeit rather tricky (and there’s a few extra features you’d clearly want to get it totally right), to implement an accurate type for Instance.new
. With the type function machinery described in the Beta announcement, we could get something almost akin to the imagined dependent type above: <InstanceName>(InstanceName) -> InstanceFrom<InstanceName>
by providing a builtin type function in Roblox named InstanceFrom
that will map string literal types (like "Part"
as a type) into the corresponding type in the type system for that instance. In the event of a string
type, it’d probably fall back to Instance
generally, and error for other types altogether. That probably provides the best overall developer experience here, but it might not happen until after the New Type Solver sees a general release (and also may not happen in exactly this form, frankly). One of the features we’d probably want for a variant of this is “bounded polymorphism” (sometimes called bounded generics or generic type bounds or a million other names) so that the type could express that InstanceName
must be a subtype of string
rather than expressing it implicitly in the definition of InstanceFrom
, e.g. something like <InstanceName: string>(InstanceName) -> InstanceFrom<InstanceName>
.
P.S. the language is named Luau, it’s a Hawaiian word pronounced like loo-ow, not the Portuguese word Lua with a capital U tacked on.