roblox-ts / types

TypeScript typings for the Roblox platform. Partially handwritten and partially automatically generated.
https://www.npmjs.com/package/@rbxts/types
MIT License
37 stars 61 forks source link

Bad type syllogisms #32

Closed headjoe3 closed 5 years ago

headjoe3 commented 5 years ago

All Instances are Folders, ValueBases, and a few other similar types. This is bad for a few reasons.

Example 1:

if (myInstance.IsA("Folder")) {
    // Do something with folders
} else if (myInstance.IsA("Part"))
    // Do something with parts
}

Example 1 will error on calling "IsA" in the else if clause, since it is of type "never" after it has been determined not to be a Folder (and since all Instances are Folders, it must not be an instance)

Example 2:


if (myInstance.IsA("Part")) {
    // Do something with parts
} else if (myInstance.IsA("Folder"))
    // Do something with folders
}

Example 2 works as a workaround for this issue in this case—however, this does not work if you have an "else" clause at the end, or are dealing with multiple all-encompassing types (like ValueBase with Folder)

Example 3:

if (myInstance.IsA("Folder")) {
    // Do something with folders
} else {
    print("Found another instance of type" + myInstance.ClassName)
}

Since all Instances are Folders, the example 3 will error, because "myInstance" is of type "never" in the else clause.

To work around this, you must use a type assertion (myInstance as Instance), or something similar, in clauses following all-encompassing type guards

Right now I have some pretty ugly code image image

evaera commented 5 years ago

This is an issue that we have actually been working on internally over the past few days before you brought this up. We're still looking for a solution that doesn't involve adding random members to these interfaces to differentiate them from Instance

osyrisrblx commented 5 years ago

Fixed this by adding a unique member to every class in the form of: __N: never; where N is a unique number to each class.

This should always appear at the bottom of the intellisense. Hopefully, in the future TypeScript will allow us to completely hide interface members from intellisense.

I'm open to suggestions on better ways to fix this.

osyrisrblx commented 5 years ago

https://github.com/Microsoft/TypeScript/issues/202