Mam stałą obiektową, że chcę wpisać. Dla zwięzłości, powiedzmy, że wygląda tak:

const obj = {
    outer1: {
        inner1: ['a', 'b'],
        inner2: ['c', 'd'],
    },
    outer2: {
        inner3: ['e', 'f'],
    },
} as const

Ten obiekt jest centralny dla mojej aplikacji, więc chcę wpisać kilka elementów do walidacji aplikacji. Nie mam problemu ograniczającego kluczy zewnętrznych i wewnętrznych jak:

type ObjType = typeof obj
type OuterKeys = keyof ObjType
type InnerKeys<KOuter extends OuterKeys> = keyof ObjType[KOuter]

Na razie w porządku. Teraz chcę utworzyć typ, który ogranicza wartości do wybranego klucza zewnętrznego i wewnętrznego. Na przykład, chcę wygenerować typ za pomocą generycznych, które stało się 'a' | 'b' dla zewnętrznej1 / wewnętrznej1. Zaczynam od rozszerzenia powyższych typów, takich jak:

type Inner<
    KOuter extends OuterKeys,
    KInner extends keyof ObjType[KOuter]
> = ObjType[KOuter][KInner]

Który wytwarza typ readonly ['a', 'b'], a nie {x1}}. Ponadto powyższy typ, aby stworzyć ten efekt, robiąc

type AOrB = Inner<'outer1', 'inner1'>[number]

Który działa idealnie. Jednak jeśli chodzi o połączenie tego do samego typu:

type Inner<
    KOuter extends OuterKeys,
    KInner extends keyof ObjType[KOuter]
> = ObjType[KOuter][KInner][number]

Otrzymuję błąd Type 'number' cannot be used to index type [constant representation of obj type]. Dlaczego tak się dzieje - i czy mogę to naprawić?

0
plusheen 13 marzec 2021, 20:58

1 odpowiedź

Najlepsza odpowiedź

Nie jestem w 100% pewien, ale myślę, że maszyny nie może wywnioskować, że twój typ wynika w tablicy z powodu leniwego typu wnioskowania. O ile mi wiadomo, maszynozapecie ocenia tylko części ogólne, musi uzyskać przyczyn wydajności. Kiedy piszesz.

type AOrB = Inner<'outer1', 'inner1'>[number]

Zmuszasz kompilatora, aby sprawdzić, jaki typ jest za obj.outer1.inner1 i zauważa, że jest to tablica. Ale jeśli piszesz

type Inner<
    KOuter extends OuterKeys,
    KInner extends keyof ObjType[KOuter]
> = ObjType[KOuter][KInner][number]

Istnieją tylko ogólne, że nie musi jeszcze oceniać, ponieważ nie określono "zewnętrznej 11" lub "Inner1" nie sprawdza, jaki typ jest za obj.outer1.inner1, a następnie fałszywie ostrzega, że możesz " t Używaj typów indeksu. Ale możesz oszukać kompilatora, wierząc, że wynik jest tablicą z Warunkowość typy:

type Inner<
    KOuter extends OuterKeys,
    KInner extends ObjKeys<KOuter>
> = ObjType[KOuter][KInner] extends readonly any[] ? ObjType[KOuter][KInner][number] : never;

W przypadku typu warunkowego kompilator jest pewien, że ObjType[KOuter][KInner] musi być tablicą, nawet bez oceny ogólnej, ponieważ w przeciwnym razie wylądowałoby w innej części, której wiemy, że nigdy się nie dzieje. To jednak trochę haky.

Edit: plac zabaw.

2
Mirco S. 13 marzec 2021, 19:20