Skip to content

Indexing a mapped type with a nested key from the original type emits compiler errors #43982

@00benallen

Description

@00benallen

Bug Report / Feature Request

When indexing a mapped type that is meant to have the same keys as an original type, the compiler emits errors when using a generic type which is a key of the original type:

Playground Link with Demonstration

https://www.typescriptlang.org/play?module=5&strict=true&ts=4.0.5&ssl=1&ssc=1&pln=43&pc=1#code/KYDwDg9gTgLgBASwHY2FAZgQwMbDgeSgQHNlMAbOAbwCg564woIwBGALmroZ4GcBXAEYAFZm068YRJMQA03HvQEixAJglTkxBXAC+8nkxbquihstEsAzBulydfIZbAAWW1p26aX0JFhwYAE8wPABpYED8dEISMkoAXjgAawiIdAIiUiQKAG4aX2h4IJC4ADlgSWAAE3DI6My4gDFoAB4AFThQVCQq3jhaqJisigA+OESUwLSM2OzyAG02gF0afPBCuGwIJEk4YmAYAGVNGUbmAFshuPG4FtDOkG7e-ojBhrnZMoenvvLKmte9VmFGaUDuIxGAApoMDyJwrh9khFOKFPkgKqgAYFOKUAJTw94UeahJbzUpLUwMKAHfhQJBwGHDBaTUno-61JZ5LxrPxFYJ4Q6Yc7AWq8dpjRK0HjExD0ybTZacKVmODE1SypFTdJtYlLJacJD8c6CNB5HhebkFfzFPAAWUwYBCVTOEEuhIScEFwtFLQRozyNAA9AAqYN0YNwNoACwQfWFMCjECqcF4if45GTAHdoElPpg+vdMD0vphqXt+KWi6hqgEIHATXAAG4UBDJyZ9aaCCAJmZMuBF5P2x3VF1u2HhuAT6N4TOYQIBKN4G19Ut4Xg0sCfBDwWOy5vkVu1zbbSRQfjYeBF2WSIu4BnpIdO0d+yiZmPYKNwKP575QTCMMQ0BgBAKgZKBEDjWNeC0fsAJYIDAgnKcYz6UAhTAcg8AoXg62zKAkj6BB0gASTgKptgAcngfh1zgNlMU1XhPgAKxo+BtjwTDG2AShpkmOBzgdMAYN3dBkGAAA6OB1S4niO3SfjBMdGDBGpTACKk8NAx5DYth2eB9iOE5iAAQR6UojRNKBn3dMyqkfGtEh0O5vmAHoC0BF9PlKVz3LKDFqgGIEmVBcEoQcBhGTiAlYU+CL6CUp8LhfTgHOdZL3TilVNRRNEAqxHEdHxVUX11Mklk+NKbNhMryQpeIxioOBA0DSN+TgCjSgozYiyQbt6zwGiaxgOtkCqUAAnaiivRFCIxRfEZdQo+K4GpGBaXpeYormeYWXmejAoiCqBKEkcMpqvaDqxPVmtatopq6nqkD6+AGyG5MRtlcaQEmkppqFWbAnm91FpJZbzVWGggA

Static Code Sample

export interface Original {
    prop1: {
        subProp1: string,
        subProp2: string
    },
    prop2: {
        subProp3: string,
        subProp4: string
    }
}

export type KeyOfOriginal = keyof Original;
export type NestedKeyOfOriginalFor<T extends KeyOfOriginal> = keyof Original[T]

export const getStringFromOriginal = <K extends KeyOfOriginal, N extends NestedKeyOfOriginalFor<K>>(original: Original, key: K, nestedKey: N): Original[K][N] {
    return original[key][nestedKey];
}

export type SameKeys<T> = {
    [K in keyof T]: {
        [K2 in keyof T[K]]: number;
    }
}

export type MappedFromOriginal = SameKeys<Original>;

/**
* This method should work, as K and N are guaranteed to be valid keys of both Original and MappedFromOriginal
*
 * The way the types are setup, it is invalid to construct an instance of MappedFromOriginal which has extra properties or is missing a property
*
 * This example also works if I don't use nested keys, just one level of key mapping is fine. 2 levels of key mapping breaks.
 */

export const getStringAndNumberFromOriginalAndMapped =
    <K extends KeyOfOriginal, N extends NestedKeyOfOriginalFor<K>>(
        original: Original,
        mappedFromOriginal: MappedFromOriginal,
        key: K, nestedKey: N
    ): [Original[K][N], MappedFromOriginal[K][N]] => { // Type 'N' cannot be used to index type 'SameKeys<Original>[K]'
        return [original[key][nestedKey], mappedFromOriginal[key][nestedKey]] // Type 'N' cannot be used to index type 'SameKeys<Original>[K]'
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions