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.