javascript - Typescript längd på en generisk typ


Jag har en funktion som ser ut som

export function is<T extends any[]>(...klasses): Predictor<T> {
    return (...variables: T) => {
        return variables
            .every((variable, index) => variable instanceof klasses[index]);
    }
}

I det här exemplet vill jag försäkra mig om att klasses har samma längd som arrayen som T är. Hur gör jag klasses av typen any[] med samma längd som T?

Uppdatering

Baserat på kommentarerna har jag uppdaterat detta till

export function is<T extends Array<any>>(...klasses: any[] & {length: T['length']}): Predictor<T> {
    return (...variables: T) => {
        return variables
            .every((variable, index) => variable instanceof klasses[index]);
    }
}

Svar #1

Här är en annan lösning som använder ett andra typargument för längden. Jag såg att du inte vill ha ett annat typargument, men jag lägger till det för fullständighetens skull ändå.

export function is<L extends number, T extends any[] & {length: L}>(...klasses: any[] & {length: L}) {
    return (...variables: T) => {
        return variables
            .every((variable, index) => variable instanceof klasses[index]);
    }
}

is(Number, String)(1, 1); // ok
is(Number, String)(1); // error

Svar #2

Du kan fråga längden på klasserna-arrayen, och sedan begränsa variablernas längd till att vara samma:

export function is<TClasses extends any[]>(...klasses: TClasses) {
    return (...variables: any[] & { length: TClasses['length'] }) => {
        return variables
            .every((variable, index) => variable instanceof klasses[index]);
    }
}

is(Number, String)(1, 1); // ok
is(Number, String)(1); // error: Types of property 'length' are incompatible

Men i det här fallet kommer du inte kunna specificera variablers typ i förväg. Om du kan ändra implementeringen för att tillåta automatisk härledning av klassers typ, kan du gå vidare med:

export function is<T extends any[]>() {
    return <TClasses extends any[]>(...klasses: TClasses) =>
        (...variables: T & { length: TClasses['length'] }) =>
            variables.every((variable, index) => variable instanceof klasses[index]);
}

is<string[]>()(Number, String)('1', '1'); // ok
is<string[]>()(Number, String)(1, 1); // error: not assignable to type 'string[]'
is()(Number, String)(1); // error: Types of property 'length' are incompatible

Relaterade artiklar