I TypeScript, hur ställer man in indexsignaturen för ett objekt som är en egenskap i en klass?


Här är en klass:

export class Survey {
    isCompleted: boolean;
    response: {
        'devices': string[];
        'languages': string[];
        'frameworks': string[];
        'backend': string[];
    };
}

Jag får felet "Elementet har implicit typen 'any' eftersom typen '...' inte har någon indexsignatur" när jag försöker följande:

return Object.keys(user1.response).map(key => {
        return percentageMatch(user1.response[key], user2.response[key]) * categoryScores[key];
    })

user1 och user2 är instanser av Survey-klassen.

Jag vet hur man ställer in en indexsignatur med enkla objektliteraler, men hur gör jag det med egenskaperna hos response-objektet, som i sig är en egenskap hos Survey-klassen.

Svar #1

Det krävdes att lägga till en indextyp [key: string]: string[] till response-typen:

export class Survey {
    isCompleted: boolean;
    response: {
        [key: string]: string[],
        devices: string[],
        languages: string[],
        frameworks: string[],
        backend: string[],
    };
}

Du kan kolla på det i TypeScript Playground-demonstrationen som jag skapade.

Du skulle också kunna överväga att minska upprepning här och extrahera kända nycklar till en strängliteraltyp:

type ResponseKeys = 'devices' | 'languages' | 'frameworks' | 'backend';

export class Survey {
    isCompleted: boolean;
    response: {
        [key in ResponseKeys]: string[]
    };
}

Svar #2

Indexsignatur krävs eftersom Object.keys() förlorar typinformation och returnerar strängarrayer.

Du kan introducera din egen funktion som liknar Object.keys() men som är deklarerad för att returnera en array med faktiska objekt-nycklar:

function typedKeys<T>(o: T): (keyof T)[] {
    // type cast should be safe because that's what really Object.keys() does
    return Object.keys(o) as (keyof T)[];
}

Då kommer det inte att bli något fel i en funktion som itererar nycklarna i ett objekt och får åtkomst till ett annat objekt, om objekten är av samma typ:

export class Survey {
    isCompleted: boolean;
    response: {
        'devices': string[];
        'languages': string[];
        'frameworks': string[];
        'backend': string[];
    };
}

function f(user1: Survey, user2: Survey) {
    return typedKeys(user1.response).map(key => {
        return user1.response[key] == user2.response[key];
    })
}

Relaterade artiklar