Currently, maintaining scripts that use arbitrary object structures, primarily related to instances as types (more on this in a moment), can be difficult when attempting to enforce type compliance. A simple typeof()
and/or :IsA()
check does not always work.
The idea I had to solve this would involve adding a new compiler-generated code option to add runtime type checking. For lack of a final name, I will say this new source option is named instanceof()
The instanceof()
function would be placed in source like such:
type BaseCharacterModel = Model & {
Humanoid: Humanoid;
HumanoidRootPart: BasePart;
}
function DoThingToCharacter(character: BaseCharacterModel)
if not instanceof(character, BaseCharacterModel) then
error("Malformed object input.", 2)
end
end
In this context, instanceof
would be generated at compile time. To achieve this, all common uses of instanceof(obj, Type)
would change into a reference to a function generated by the Luau compiler that ensures obj
, at the least, has all of the mandated fields of the given type. obj
is allowed to have more fields if it must, allowing supertypes to be used in this function.
This function will return true if the type of all values in the given object match that of the type declaration. For types like Instance, it uses IsA()
, for dictionary types {[TKey]: TValue}
and native types it simply checks if the type of the object’s corresponding value is table
or the other Lua(u) native type via generating code that uses typeof()
, but for explicitly defined structures, it will check individual indices and value types.
If the input type is a union between multiple types, then it will generate a function for each compliment of the set of types, that is,
type A = {
V0: number;
}
type B = A & {
V1: number;
}
type C = B & {
V2: number;
}
-
instanceof(obj, A)
would only check for the existence of V0 -
instanceof(obj, B)
would begin by callinginstanceof(obj, A)
, and iff that was successful, it continues by checking for the parts uniquely added by B (V1). This is because type unions are strictly additive, so some time can presumably be saved by checking the least common denominator of the types first. -
instanceof(obj, C)
would layer on this by checkingA
first, then checkingB
, and finally checkingC
in that order.
The implementation of this function would allow for the types to be dominant features during runtime without actually exposing types to the runtime environment.