luau icon indicating copy to clipboard operation
luau copied to clipboard

Nested tagged unions do not work as I want them to work

Open 0x13479 opened this issue 1 year ago • 1 comments


type CircularEntity = {
	shape: 'Circular',
	only_for_circular: any,
}

type RectangularEntity = {
	shape: 'Rectangular',
}

type Entity = CircularEntity | RectangularEntity

local entity: Entity = {} :: any

if entity.shape == 'Circular' then
	print(entity.only_for_circular) -- OK ✅
end
if entity.shape == 'Rectangular' then
	print(entity.only_for_circular) -- Warning ✅
end

in the above case , tagged unions work as expected . in the implementation below , they do not :


type CircularEntity = {
	parameters: {
		shape: 'Circular',
		only_for_circular_inside: any,
	},
	only_for_circular: any,
}

type RectangularEntity = {
	parameters: {
		shape: 'Rectangular',
	},
}

type Entity = CircularEntity | RectangularEntity

local entity: Entity = {} :: any

if entity.parameters.shape == 'Circular' then
	print(entity.only_for_circular) -- Warning ❌
	print(entity.parameters.only_for_circular_inside) -- OK ✅
end
if entity.parameters.shape == 'Rectangular' then
	print(entity.only_for_circular) -- Warning ✅
	print(entity.parameters.only) -- Warning ✅
end


here is my ideal use case :




type DamageModel = ModelCommon & {
	modifier: {
		Value: 'Damage',
	},
	damage_part: Part,
}

type HealModel = ModelCommon & {
	modifier: {
		Value: 'Heal',
	},
}

type ModelCommon = Model & {
	modifier: StringValue,
}

type MyModel = DamageModel | HealModel

local model: MyModel = {} :: any
if model.modifier.Value == 'Damage' then
	print(model.damage_part) -- Warning
end

i have to do this since there is no typechecking for attributes , perhaps if there is a way to accomplish this , i'll be thankful if you let me know .

0x13479 avatar Mar 09 '24 17:03 0x13479

for attributes you could make it work like this :




type HealingButton = ButtonCommon & {
	GetAttribute:
		((ButtonCommon, "Class") -> ('Healing')),
	health: IntValue,
}

type DamageButton = ButtonCommon & {
	GetAttribute:
		((ButtonCommon, "Class") -> ('Damage')),
	damage: IntValue,
}

type ButtonCommon = Model & {}

type Button =
	HealingButton |
	DamageButton

local button: Button = {} :: any

-- Type Error: (24,4) Cannot call non-function (((Instance, string) -> any) & ((Model, "Class") -> "Damage")) | (((Instance, string) -> any) & ((Model, "Class") -> "Healing"))
if button:GetAttribute("Class") == 'Damage' then
	-- Type Error: (26,8) Key 'damage' is missing from 'Model & {|  |} & {| GetAttribute: (Model, "Class") -> "Healing", ... 1 more ... |}' in the type '(Model & {|  |} & {| GetAttribute: (Model, "Class") -> "Damage", ... 1 more ... |}) | (Model & {|  |} & {| GetAttribute: (Model, "Class") -> "Healing", ... 1 more ... |})'
	print(button.damage)
end

0x13479 avatar Mar 10 '24 10:03 0x13479