microsoft / microsoft/TypeScript

"Lookup" Type Broken When Using Generics

Đang mở
#62,770 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Domain: Mapped Types Help Wanted Possible Improvement
Ngôn ngữ chính
Go
Star
111k
Fork
14.3k
Merge trung bình
2 ngày 4 giờ
Pull request đã merge (30 ngày)
132

Mô tả

🔎 Search Terms

"nested lookup with generic", "type lookup with generic"

🕗 Version & Regression Information
  • For doesNotWork1, this changed between versions 3.9.7 and 4.0.5.
  • For other "not working" examples, this is the behavior in every version I tried, and I reviewed the FAQ for entries about generics within lookup tables.
⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.9.3#code/JYOwLgpgTgZghgYwgAgOrDACwMIHsC2+uIyA3gFDJXIzAQA2AJgIwBcyIArvgEbQDclarQaMATOwDOYKKADmggL7lyoSLEQp0WAMoAHCAmBx6yCAA9IIRpLQYcBIiQrVkkg0ZPsuvAeWWq4NDwSMj6hsb0ADK4uADWnHpkQlTuEV52uh6RSipqwZrIeITEMfGJZpYQ1rbhntGxCUku1AiOxOzaDiUgueRgAJ4GyGVNADwAcnD4KBZWNshxEAO4MEXtIKOJAHzIALzJrgDaANLIoIvLq+s9W3pHUzMAuk8A-OzFTncP0xBPp08lIJyAB6EHICYAeQAKgBRdhYYC2JHIHhQeLVMwAN0xAHd7MgAAZLFZrT6lRqJQnIQAoBJcBkS0vVqZg4LYwLhUSg2oRqpBGMhcJwwDRcFBKtM9PQUFg4CLGJyQLgRbixXFkBy3BBZlB0VBbFAIGBOFAQOQYJwQAgwMBiG4CBBHhAxmc5tUFiTrnVIndtgAKACU7CxuGAApaVDaIGkyFVUDikjYI0pejGAHImZE07sDhHXDQ6Ewk8wADQpfMiJgSZBpnlONNl-PUTMZMQABgAzI3qIpga4ozG4wnq3d03XiNn9ocmwXREmAKzdpuV8TsDMOxEgOQN8uuMHINq6wxgegM2g1DWskWI2wrtyYIVMDjKrmX6AQXfN7IZDtiJfIXsVD3cELA8MA5VtEgUVlEVCUtRgIHPCBGGpSQH04J8+GQEx6FwXFkOQRhOBlTk9HRAwoEGDUhggWw0Lw+RLzlc4RXojCBT4ct9yhOEEUwFEACpcTZATYzVRiLixDsADoAE5pIAdnLAd5VwWiJmVVA1STUcThzacm33P0yNwCjBgDNxv3od4bi+FMASOAAiFt6Ecp5kAAH2QeDENAAi6UkTlmPwUBgHwbhLxRNjMJQQ1AvoHENU5ODrF8kBkNQ0BQkJdKcXFLyfKQlDkDi3AEtopKiUKvyUOkurP1SKz2Gq9LGH-VwVyTFrkPa4RC1XbzUqK-9AK4kDzDAiC7Wgq9ItsVV2NfOAeGlSrD0Na1T3OBDwGAGAz365ESHHEgYDFObLIiWgEC1EVrhJSQxohGF4QuhUKqVFU1XOEg4BABk8skSDsKxOBgHoZbVouKU4AGOR0Xg5TiBjd7JA0sAtPjEcUxdfS81cFz2GYNs2wAFhGoDqH3UDjymqD2Vmm8xMWrDIZIg8xQ2k8GTDPk9oO0Qjo5npYwJHCJXwKVaKenjXqZ1Hny++Mfuw-7kEB4G4FB8G2ZVmG4YR6wkejVT1M0tUO3YXS8Ya2ciyJxdbZXas0z+5VMGgNNy2UZQgA

💻 Code
interface WithCommon {
    field1: number;
    field2: string;
}

interface WithSpecial extends WithCommon {
    special: number;
}

interface SpecialLookup {
    special: WithSpecial;
}

interface CommonLookup extends SpecialLookup {
    common: WithCommon;
}

type Lookup<Name extends keyof CommonLookup> = {
    [K in keyof CommonLookup[Name]]?: CommonLookup[Name][K];
};

// NOTE: this is broken even with `keyof CommonLookup` — key `special` has to be removed to see current error return since with `CommonLookup` we do detect that `special` is not a shared key of all members
function someName<K extends keyof SpecialLookup>(): void {
    const works1: Lookup<'special'> = {
        field1: 1,
        field2: 'common',
        special: 203,
    };

    const works2: Lookup<'common'> = {
        field1: 5,
        field2: 'something',
        // correctly finds that this field should not be there
        special: 32,
    };

    // expectation is that `undefined` should be allowed due to property types showing that it should be
    // NOTE: this *was* working in v3.9.7
    const doesNotWork1: Lookup<K> = {
        // (property) special?: CommonLookup[K]["special"] | undefined — so at minimum this should be resolve to `undefined` since `never | undefined` resolves to `undefined`...
        special: undefined,
        field1: undefined,
        field2: undefined,
    };

    // expectation is that this would be able to correctly identify fields in common for this specific set of keys
    // NOTE: this does not work in any version available in playground
    const doesNotWork2: Lookup<K> = {
        special: 1004,
    }

    // expectation is that this would be able to correctly identify fields in common with all examples
    // NOTE: this does not work in any version available in playground
    const doesNotWork3: Lookup<K> = {
        field1: 15,
        field2: 'another'
    }
}
🙁 Actual behavior

When using a generic as the input to a "lookup" type, we should be able to correctly type the common fields of the "looked-up" interfaces.

What is interesting here is that we appear to get correct behavior from "code completion" (i.e. special is correctly typed as a property of Lookup<K> with type CommonLookup[K]["special"] | undefined), but actually setting the presented type value doesn't work.

🙂 Expected behavior

We should get correct typing for the generic Lookup<K> type:

  • doesNotWork1 should allow undefined as a value since field type evaluates to CommonLookup[K][Field] | undefined.
  • doesNotWork2 should allow number as value for field special since all interfaces within keyof SpecialLookup have special: number on the interface.
  • doesNotWork3 should allow values for field1 and field2 for the same reason as doesNotWork2.
Additional information about the issue

As I called out in my NOTE within the code example, this is also broken in a "simpler" example where the generic is K extends keyof CommonLookup. I presented the above code example because it is the most similar to my use case and I wasn't sure if fixing the "simpler" case would also fix the one where we are choosing a smaller key set.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với TypeScript Playground được liên kết và tái hiện các ví dụ doesNotWork1–3 trên các phiên bản trình biên dịch đã nêu. Theo dõi hành vi kiểm tra kiểu của generic lookup, sau đó xác minh rằng các phép gán undefined và các trường chung như mong đợi đều được kiểm tra kiểu mà không cho phép các trường không hợp lệ.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
typescript
Lĩnh vực
compilers
Loại issue
Lỗi
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.