why mapping of array not work same ad mapping record?

is there a reason why mapping an array does not work the same way as mapping a record?
An array is, in itself, an iterable object just like a Record<number, …>, right ?

In this code, you can observe the desired behavior for ParamRecordRecord.
This gives me a data table with methods that have a parameter automatically inferred based on the data context.

I also need a version in the form of a record for arrays.
ParamRecordArray is therefore an exact copy of ParamRecordRecord, except that instead of having keys enumerated in enum BBB, the keys are the array indices.
However, for some reason, I cannot reproduce the same behavior as the table above.
All parameters in the methods components are numbers.

a mark in red🔴 where the issue occur

enum AAA { a1 = 'a1', a2 = 'a2', a3 = 'a3' }
enum BBB { b1 = 'b1', b2 = 'b2', b3 = 'b3' }

// the data structure
type TestData<T extends number = number> = {
    _: string;
    components?: T[];
    check: (c: T) => void;
}

// version record of record

type ParamRecordRecord<T> = {
    [KA in keyof T & AAA]: {
        [KB in keyof T[KA] & BBB]?: TestData<Extract<T[KA][KB], number> extends never ? number : Extract<T[KA][KB], number>>
    }
}

new class TestRecorRecord<T> {
    constructor(data: ParamRecordRecord<T>) { }
}(
    {
        [AAA.a1]: {
            [BBB.b1]: {
                _: '',
                check: (c) => { } //🟢number
                //     ^?
            },
        },
        [AAA.a2]: {
            [BBB.b2]: {
                _: '',
                components: [1],
                check: (c) => { }//🟢1
                //     ^?
            },
            [BBB.b1]: {
                _: '',
                components: [2],
                check: (c) => { }//🟢2
                //     ^?
            },
        },
    }
)



// version record of array

//This is a copy of ParamRecordRecord, except that the iteration is done over the index of the object array.
//The index keys are numbers or `${number}`, rather than strings coming from the BBB enumerator.
type ParamRecordArray<T> = {
    [KA in keyof T & AAA]: {
        [KB in keyof T[KA] & `${number}`]?: TestData<Extract<T[KA][KB], number> extends never ? number : Extract<T[KA][KB], number>>
    }
}

new class TestRecorArray<T> {
    constructor(data: ParamRecordArray<T>) { }
}(
    {
        [AAA.a1]: [
            {
                _: '',
                check: (c) => { }//🟢number
                //     ^?
            },
        ],
        [AAA.a2]: [
            {
                _: '',
                components: [1],
                check: (c) => { }//🔴1
                //     ^?
            },
            {
                _: '',
                components: [2],
                check: (c) => { }//🔴2
                //     ^?
            },
        ],
    }
)


//ok not work so let try debug ?
type debug = ParamRecordArray<{ [AAA.a1]: [ TestData<1>, TestData<2> ] }>
//   ^?
// ya it seem not able to extract the generic , but am not understand why !?

playground

Thank you in advance for your clarification and for a solution if possible.

NOTE: i dont want use as const or a function<const T>():T everywhere for each entries just for array versions.
const T in the class can be a solution but seem not work !

I also could have used a single wrapper, but the const T type doesn’t seem to handle nested Record<string, TestData[]> in this case.

5

You’ve run into a longstanding bug reported at microsoft/TypeScript#27995 where mapped types over array and tuple types don’t quite behave like homomorphic mapped types (see What does “homomorphic mapped type” mean?) unless the type being mapped over is a generic type parameter. If T is a generic type parameter, then {[K in keyof T]: F<T[K]>} will map array types to array types and tuple types to tuple types. But otherwise it will map over all the keys of the array type including things like "length" and "push". Homomorphic mapped types allow for inference of T from a value of type {[K in keyof T]: F<T[K]>}, and this sort of inference is what you need for your code to work. It isn’t happening, so you’re getting bad inference.

This is considered a bug but it’s not clear when or if it will ever be fixed. Until and unless that happens, you can work around it by just refactoring so that the type being mapped over is a generic type parameter; that is, make a utility type:

type ParamRecordArray<T> = {
    [KA in keyof T & AAA]: F<T[KA]>
}

type F<T> = { [KB in keyof T]?: TestData<
    Extract<T[KB], number> extends never ? number : Extract<T[KB], number>
> }

Here F<T[KA]> is doing what your original { [KB in keyof T[KA] & ${number}]?: ⋯ } was doing. Note that there’s no reason to intersect with `${number}` since all that will do is break the homomorphic mapping and prevent the inference you need, and homomorphic mapped array/tuples already only iterate over the numeric-like indices.

Let’s make sure it works:

const z = new class TestRecorArray<T> {
    constructor(data: ParamRecordArray<T>) { }
}(
    {
        [AAA.a1]: [
            {
                _: '',
                check: (c) => { }//🟢number
                //     ^? (parameter) c: number
            },
        ],
        [AAA.a2]: [
            {
                _: '',
                components: [1],
                check: (c) => { }//🟢1
                //     ^? (parameter) c: 1
            },
            {
                _: '',
                components: [2],
                check: (c) => { }//🟢2
                //     ^? (parameter) c: 2
            },
        ],
    }
)

Looks good!

Playground link to code

1

The problem is because TypeScript with arrays and types Arrays use numbers as keys and TypeScript has trouble guessing the right type for each item.

so to fix it use a helper type to grab the type inside the array. this will help the TS understand what type should expect.

type ArrayElement<A> = A extends readonly (infer T)[] ? T : never;

type ParamRecordArray<T> = {
    [KA in keyof T & AAA]: T[KA] extends readonly any[] ? {
        [KB in keyof T[KA] & `${number}`]?: TestData<ArrayElement<T[KA]> extends number ? ArrayElement<T[KA]> : number>
    } : never
}

3

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật