Dynamic Type Definitions for Selection:Get()

As a Roblox developer, it is currently impossible to get accurate type information from the Selection:Get() method, as it always returns a static type definition of { Instance }, regardless of the actual types of selected objects in Studio.

If this issue is addressed, it would improve my development experience because it would provide precise type information within the Command Bar, enabling much better support for autocomplete.

Use Case

When using the Command Bar, I frequently need to perform operations on specifically selected objects. The current static type definition of Selection:Get() as { Instance } fails to convey the actual types or number of selected objects, resulting in missing and/or incorrect autocomplete suggestions.

Proposed Solution

Implement a dynamic type definition system for Selection:Get() that accurately reflects the types of currently selected objects in Studio. For example:

  • When selecting a workspace.Part and ReplicatedStorage.LocalScript, game.Selection:Get() should be typed as { Part, LocalScript }
  • When nothing is selected, it should be typed as {}

This dynamic typing would dramatically improve the Command Bar experience.

3 Likes

This isn’t even theoretically possible. Type systems by nature are static and are completely blind to the actual runtime values they represent.

Luau doesn’t even have a concept for mixed arrays currently, so a type like {Part, LocalScript} would be unrepresentable.

1 Like

This request should really be more of an “add strict arrays” request because the language is currently very unsafe to use with that type of data. There’s no reason for a “type safe” language to not have it because it’ll lead to either unsafe code or slower than neccessary code.

local function unsafe(tupleData: {string | number})
	local value = tupleData[1] :: string
	local repeatCount = tupleData[2] :: number
	return string.rep(value, repeatCount)
end

local function slow(tupleData: {string | number})
	local value = tupleData[1]
	if type(value) ~= "string" then
		warn("Expected string for value")
		return ""
	end

	local repeatCount = tupleData[2]
	if type(repeatCount) ~= "number" then
		warn("Expected number for repeatCount")
		return ""
	end

	return string.rep(value, repeatCount)
end

unsafe({"hello", 3}) -- totally fine
unsafe({3, "hello"}) -- still "valid" in Luau's eyes but not safe

slow({"hello", 3}) -- this is fine
slow({3, "hello"}) -- sure, it'll run, but it's also horrendously slow!

whereas in something like TypeScript it’s just…

function noUnsafeOrSlow(tupleData: [value: string, repeatCount: number]) {
	const [value, repeatCount] = tupleData;
	return value.rep(repeatCount);
}

noUnsafeOrSlow(["hello", 3]); // totally fine
noUnsafeOrSlow([3, "hello"]); // it yells at you! like it should!
1 Like