Búsqueda de sitios web

typescript - Imponiendo los tipos del valor de la interfaz


Estoy trabajando en aprender Typescript y estoy tratando de entender cómo aplicar tipos basados en una interfaz.

Tengo este fragmento de código

    interface User{
    name:string;
    age:number;
    friends:string[]
    hasPet:boolean
}

function setValue<T>(key:keyof T, value: T[keyof T] ):void{
    console.log(key, value)
    // ...some additonal logic
}

setValue<User>("age", true )  //should throw error but doesn't

Quiero que esta interfaz haga cumplir el tipo de clave cuando llame a setValue. Esto funciona en su mayoría, pero puedo pasar cualquiera de los tipos de Usuario disponibles a setValue.

Lo que espero es que al pasar "age" como el primer argumento a setValue, el segundo argumento esté restringido al tipo "number". Lo mismo para todas las demás claves de Usuario también.

¡Gracias por la ayuda!

Respuesta #1

Deberías inspeccionar esto en el playground de Typescript. La razón por la que no lanza un error es que keyof devuelve un tipo que representa todas las claves de las propiedades.

Así que tu función en realidad se ve así:

setValue(key: keyof User, value: string | number | boolean | string[])

Obviamente, lo que estás intentando hacer encaja en uno de esos tipos.

Donde si intentaras hacer algo como:

let newUser: User;
newUser.age = 'abc'; // Type error

Respuesta #2

Para una inferencia de tipo correcta, la clave también debe ser una variable de tipo.

Déjame adivinar, pero en una aplicación real, lo más probable es que tengas una función como

function setValue<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
    obj[key] = value;
}

const user: User = {
    name: 'Den',
    age: 22,
    friends: ['1'],
    hasPet: true,
};

setValue(user, 'age', true); // Error - Argument of type 'boolean' is not assignable to parameter of type 'number'

Porque en tu ejemplo, la función tiene parámetros para la clave y el valor, pero no hay ningún objeto que cambiar.


Otra solución alternativa si necesitas una función seter por alguna razón:

const createValueSetter = <T>(obj: T) => <K extends keyof T>(
    key: K,
    value: T[K]
) => {
    obj[key] = value;
};

const user: User = {
    name: 'Den',
    age: 2,
    friends: ['1'],
    hasPet: true,
};

const userSetter = createValueSetter(user);

userSetter('age', true); // Error - Argument of type 'boolean' is not assignable to parameter of type 'number'