Explore marking arrays with a metatable · Issue #535 · TypeScriptToLua/TypeScriptToLua · GitHub
Skip to content

Explore marking arrays with a metatable #535

Open

Description

@ark120202

Since now there is no difference between {} and [], it's impossible to implement a stable Array.isArray. Transpling array literals to setmetatable({}, ____arrayMetatable) gives required data for Array.isArray and doesn't affect performance too much.

A major issue is that there would be a need for a new decorator (or a type) to mark functions that return standard lua arrays, and then set the metatable of returned values.

Activity

  1. tomblind commented on Apr 24, 2019

    @tomblind
    Collaborator

    I definitely think this should be optional, so folks can keep things as minimal lua if they desire.

    Also, is a metatable even needed? Something like this could work:

    ____TS_isArray = {}
    ...
    local myArray = {[____TS_isArray] = true}
  2. ark120202 commented on Apr 24, 2019

    @ark120202
    ContributorAuthor

    I definitely think this should be optional

    Any flags that affect transpilation have a major issue - using files built with different options won't work (which is especially important for lualib).
    A metatable has a low performance cost on 5.3 and doesn't affect performance on JIT at all, so IMO an option doesn't worth the issues it has.

    Also, is a metatable even needed?

    Not really, any special mark would do it. I think metatable may work better with some native environment functions that would iterate over an array.

  3. pilaoda commented on Aug 11, 2025

    @pilaoda
    Contributor

    Hi. I would like to add a PR about this.

    Proposed Solution

    I propose a new, class-based Array implementation, enabled by an opt-in tsconfig.json setting like "arrayClass": true. All array will use this class to construct. Except Array.isArray, other Array static and non-static methods will still compiled to use lualib implementations.

    _G.Array ??= class Array {
        public static isArray(arg: any): arg is any[] {
            return arg instanceof _G.Array;
        }
    } as ArrayConstructor;
    

    This would provide:

    • A reliable way to distinguish [] and {}.
    • The ability to extend the Array class (class MyArray extends Array {}).
      Making this optional ensures no breaking changes or performance impact for existing projects.

    The lualib Implementation Challenge

    A simple opt-in feature is difficult due to the static, pre-compiled lualib_bundle.lua.

    Core functions within this bundle, like __TS__ArrayMap, internally create new arrays (e.g., const result = []). This code is part of the static bundle and cannot be compiled conditionally based on a user's tsconfig.json options. This prevents library functions from correctly creating class-based arrays when the feature is enabled.

    Potential Solutions

    1. Dynamic lualib output:

      • Compile all lualib functions (__TS__ArrayMap, etc.) to create arrays via a new internal helper, e.g., __TS__NewArray(rawTable?:any[]).
      • Default __TS__NewArray just return raw table, but return Array instance if "arrayClass": true, so we need some way to modify the output of __TS__NewArray in compile time (Pls tell me the right way to do this), and the performance impact of calling __TS__NewArray function will be inevitable.
    2. No arrayClass options, always use Array class.
      This is a Big change, but I believe this is the right way.

    @Perryvw Please tell me your thought about this, then I can decide what to do.

  4. Perryvw commented on Aug 11, 2025

    @Perryvw
    Member

    I don't think adding this would be worth the trouble. If you want this special data structure for some reason you can define your own class, no need to mainline it into core tstl

  5. Zamiell commented on Aug 11, 2025

    @Zamiell
    Contributor

    In order to use a custom class for this purpose, one would have to use a plugin to override the Array implementation right?

  6. pilaoda commented on Aug 12, 2025

    @pilaoda
    Contributor

    I don't think adding this would be worth the trouble. If you want this special data structure for some reason you can define your own class, no need to mainline it into core tstl

    The main reaason for me is to distinguish [] and {}, so I am suppose to use my custom plugin to solve this right? Even I write my custom plugin to override array transform, there are still some raw table defined in lualib.
    Not only for this trouble, it is more ECMAScript standand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions