3

I'm trying to create a dictionary data structure that contains several CustomType objects that can be associated with any string key.

I figured I could just use {[string]: CustomType} as my dictionary type, like this:

--!strict
type CustomType = {
    a: string,
    b: string
}

local dictionary: {[string]: CustomType} = {
    keyOne = { a = 'hello' }, -- should display type error ('b' field missing)
    keyTwo = { a = 'hello', b = 'world'} -- should be fine
}

However, in the code snippet above no type error is shown in the code editor even though the b field is missing from keyOne. Yet, if I explicitly define the keys in the dictionary type definition, then it works as expected:

--!strict
type CustomType = {
    a: string,
    b: string
}

local dictionary: {keyOne: CustomType, keyTwo: CustomType} = {
    keyOne = { a = 'hello' }, -- displays type error
    keyTwo = { a = 'hello', b = 'world'} -- is fine
}

Why is this? I would like to enforce strict typechecking for all generic string keys without needing to explicitly define them in the dictionary type definition. Am I going about this the wrong way? Could this be a ROBLOX issue (since I am implementing this in the ROBLOX engine)?

Any help would be greatly appreciated.

Source/info about Luau typechecking: https://luau-lang.org/typecheck

5
  • I remember having a similar problem. I'm not sure, but it could be because of keyOne being considered differently combined with duck typing. Could you try using the value key syntax and a string literal? Like ["key"] = value? Commented Aug 31, 2022 at 15:59
  • @Random Interesting. Yeah, I tried it using the string literal syntax for the key/value pairs like ['keyOne'] = { a = 'hello' } but it doesn't seem to make any difference. Commented Aug 31, 2022 at 16:04
  • I've just tested it myself and it seems like what I said wasn't the case. For example, instead of omitting b, give it a value like nil, 1 or true; and it displays a type error. Using a variable makes it work normally. This could be a bug. Commented Aug 31, 2022 at 16:14
  • 1
    Someone just opened an issue, in case that wasn't you. Commented Aug 31, 2022 at 16:16
  • @Random You're right, I also noticed that before posting the initial question. I spoke to someone about this behavior and they opened that github issue for it. I appreciate the comments! Commented Sep 6, 2022 at 18:04

1 Answer 1

2

Unfortunately, in current Luau (0.545 as of this writing in September 2022), once you have an indexer ([string]) in your type, the rest of the keys on the type will not be checked in the way you expect.

Using indexers can definitely be a nice ergonomic improvement over explicit method calls, but besides the type system not quite giving the safety you want in those cases, it can sometimes be slower than the explicit method call approach.

When overriding __index, __newindex, and/or __call on tables for better ergonomics, make sure you aren't unknowingly opting out of type safety, or increasing runtime overhead in the hot path of your Luau application.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.