Tagged unions, as shown on the documentation, work on separated table declarations:
type Ok<T> = { type: "ok", value: T }
type Err<E> = { type: "err", error: E }
type Result<T, E> = Ok<T> | Err<E>
if result.type == "ok" then
-- result is known to be Ok<T>
-- and attempting to index for error here will fail
print(result.value)
elseif result.type == "err" then
-- result is known to be Err<E>
-- and attempting to index for value here will fail
print(result.error)
end
However, if we had a “baseType”, we cannot simply add a tagged union to it:
type recipe = {
eggs: number,
bacon: number,
} & ({
hasNutAllergy: false,
peanuts: number,
walnuts: number,
} | {
hasNutAllergy: true,
subsituteIngredient: string,
amount: number,
})
local sampleRecipe: recipe = --> some recipe
if sampleRecipe.hasNutAllergy then
sampleRecipe.subsituteIngredient --> does not autofill
else
sampleRecipe.peanuts --> does not autofill
end
There is a workaround, however. You can intersect the different tagged types to the base type first, then union them together:
type baseRecipe = { --> creating a base type
eggs: number,
bacon: number,
}
type nutRecipe = {
hasNutAllergy: false,
peanuts: number,
walnuts: number,
} & baseRecipe --> intersecting the tag with the base type
type nutlessRecipe = {
hasNutAllergy: true,
subsituteIngredient: string,
amount: number,
} & baseRecipe --> intersecting the tag with the base type
type recipe = nutRecipe | nutlessRecipe --> unioning both types together
local sampleRecipe: recipe
if sampleRecipe.hasNutAllergy then
sampleRecipe.subsituteIngredient --> autofills
else
sampleRecipe.peanuts --> autofills
end
This is unfortunately quite clunky and undesirable.
Expected behavior
Tagged table types should autofill even if they’re added as a intersection type:
local sampleRecipe: recipe = --> some recipe
if sampleRecipe.hasNutAllergy then
sampleRecipe.subsituteIngredient --> autofills
else
sampleRecipe.peanuts --> autofills
end