HttpService:JSONEncode formats some DataTypes wrong

Calling HttpService:JSONEncode with the following datatypes as a key in a table will parse them as incorrect strings.

Enums -- <null>
Enum -- <null>
EnumItem -- <token>
OverlapParams -- <null>
RotationCurveKey -- <null>
BrickColor -- <int>
CFrame -- <CoordinateFrame>
Rect -- <Rect2D>

I expect them to be in the format <typeof(KEY)> (tostring(KEY))

Repro

local HttpService = game:GetService("HttpService")

print(HttpService:JSONEncode({[Enum] = 1})) -- <null>
print(HttpService:JSONEncode({[Enum.KeyCode] = 2})) -- <null>
print(HttpService:JSONEncode({[Enum.KeyCode.One] = 3})) -- <token>
print(HttpService:JSONEncode({[OverlapParams.new()] = 4})) -- <null>
print(HttpService:JSONEncode({[RotationCurveKey.new(0, CFrame.identity, Enum.KeyInterpolationMode.Constant)] = 5})) -- <null>
print(HttpService:JSONEncode({[BrickColor.new(248, 248, 248)] = 6})) -- <int>
print(HttpService:JSONEncode({[CFrame.identity] = 7})) -- <CoordinateFrame>
print(HttpService:JSONEncode({[Rect.new()] = 8})) -- <Rect2D>

Output:

{"<null> (Enums)":1}
{"<null> (KeyCode)":2}
{"<token> (Enum.KeyCode.One)":3}
{"<null> (OverlapParams{MaxParts=false, BruteForceAllSlow=false, RespectCanCollide=false, CollisionGroup=Default, FilterDescendantsInstances={}})":4}
{"<null> ({Constant, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0})":5}
{"<int> (Institutional white)":6}
{"<CoordinateFrame> (0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1)":7}
{"<Rect2D> (0, 0, 0, 0)":8}

Serialization of Lua tables on Roblox generally only supports arrays (sequential integer keys) and objects (string keys). The documentation explicitly calls this out as being the case for JSONEncode: HttpService | Documentation - Roblox Creator Hub

Ideally we would error for other unsupported keys in this case but changing that now would likely break too much code, so we have to stick with the existing behavior.

If you want to make your code work you can explicitly construct the table you want by calling typeof yourself.