typescript - Skapa arrayer av generiska gränssnitt


Låt oss säga att vi har följande gränssnitt:

interface I<A extends string, B extends string> {
    a: A,
    b: B,
    c: `${A} ${B}`
}

Jag vill skapa en funktion som gör en array av I och validerar dess typer så att

makeArr([
    {
        a: "1",
        b: "2",
        c: <- it should have type "1 2" | "3 4"
    },
    {
        a: "3",
        b: "4",
        c: <- it should have type "1 2" | "3 4"
    }
])

Jag har redan försökt implementera det så här:

type Arr<A extends string, B extends string> = I<A, B>[]

function makeArr<A extends string, B extends string>(arr: Arr<A, B>) {
    return arr
}

Dock accepterar c-egendomen fortfarande vilken sträng som helst

makeArr([
    {
        a: "1",
        b: "2",
        c: "this does not work"
    },
    {
        a: "3",
        b: "4",
        c: "whatever "
    }
])

Det fungerar lite bättre när du specificerar typerna uttryckligen, men c accepterar ändå några felaktiga typer

makeArr<"1" | "3", "2" | "4">([
    {
        a: "1",
        b: "2",
        c: "3 2"
    },
    {
        a: "3",
        b: "4",
        c: "1 4"
    }
])

Jag skulle inte heller vilja specificera det uttryckligen, eftersom de där arrayerna kan vara väldigt långa

Redigera: Tack vare aleksxors svar lyckades jag implementera det, men typerna måste anges uttryckligen Playground-länk

Svar #1

Jag tror att det måste finnas ett mer elegant sätt. Men här är mitt försök att implementera en sådan kontroll:

type I<T extends { a: string, b: string }> = T extends {
    a: T['a'],
    b: T['b'],
    c: `${T['a']} ${T['b']}`
} ? T : never

function makeArr<T extends { a: string, b: string }>(arr: readonly [...I<T>[]]) {
    return arr
}

makeArr([
    {
        a: "1",
        b: "2",
        c: "doesn't pass"
    },
    {
        a: "3",
        b: "4",
        c: "3 4"
    }
])

lekplatslänk

Relaterade artiklar