Búsqueda de sitios web

En TypeScript, ¿cómo establecer la firma de índice de un objeto que es propiedad de una clase?


Aquí hay una clase:

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

Estoy recibiendo el error "Elemento tiene implícitamente un tipo 'any' porque el tipo '...' no tiene una firma de índice" al intentar lo siguiente:

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

user1 y user2 son instancias de la clase Survey.

Sé cómo establecer una firma de índice con literales de objeto simples, pero ¿cómo lo hago con las propiedades del objeto response, que a su vez es una propiedad de la clase Survey?

Respuesta #1

Eso requería añadir un tipo de índice [key: string]: string[] al tipo response:

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

Puedes revisarlo en la demostración de TypeScript Playground que creé.

También podrías considerar reducir la repetición aquí y extraer las claves conocidas a un tipo literal de cadena:

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

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

Respuesta #2

Se requiere una firma de índice porque Object.keys() pierde información de tipo y devuelve arrays de cadenas.

Puedes introducir tu propia función que sea similar a Object.keys(), pero que se declare para devolver un arreglo de claves reales del objeto:

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)[];
}

Entonces, no habrá error en una función que itera sobre las claves de un objeto y accede a otro objeto, si los objetos son del mismo tipo:

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];
    })
}

Artículos relacionados