Búsqueda de sitios web

ecmascript 6 - ¿Cómo hacer esto en Typescript: usar el valor predeterminado cuando la propiedad calculada no existe?


Cuando uso Propiedad Computada en JavaScript, puedo escribir mi código así

const def_val = {a:"debug",b:"info",c:"warning"};

function work(y) {
    let x = def_val[y] || def_val.a /* if y is not a or b or c */
}

¿Pero cómo hago que eso funcione en TypeScript?

const def_val = {a:"debug",b:"info",c:"warning"};

function work(y: string) {
    let x = def_val[y] || def_val.a;
}

Recibí el error del compilador

error TS7053: El elemento tiene implícitamente un tipo 'any' porque una expresión de tipo 'string' no se puede usar para indexar el tipo '{ a: string; b: string; c: string; }'.

No se encontró ninguna firma de índice con un parámetro de tipo 'string' en el tipo '{ a: string; b: string; c: string; }'.

He buscado en SO pero solo puedo encontrar Cómo establecer una variable si está indefinida en TypeScript, lo cual no es mi pregunta.

Ahora cambié mi código ts a esto, pero se siente tedioso comparado con el código js original

function work(y: string) {
    let x:string
    if (y!='a' && y!='b' && y!='c') {
        x = def_val.a;
    } else {
        x = def_val[y]
    }
}

---- actualización ----

@captain-yossarian la respuesta es una forma de arreglarlo, por ejemplo, const def_val: Record<string, string>={ a: "debug", b: "info", c: "warning" };

Encuentro que la otra manera de solucionarlo es usar keyof typeof, consulta aquí https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types para más información, por ejemplo, "En JavaScript es bastante común tener APIs que esperan nombres de propiedades como parámetros, pero hasta ahora no ha sido posible expresar las relaciones de tipos que ocurren en esas APIs.", ¡exactamente mi caso aquí!!

const def_val = {a:"debug",b:"info",c:"warning"};

function work(y:keyof typeof def_val) {
    let x = def_val[y] || def_val.a;

}

Obtuve esta respuesta de Cómo acceder dinámicamente a la propiedad de un objeto en TypeScript

Respuesta #1

def_val es inferido por TypeScript como

const def_val: {
    a: string;
    b: string;
    c: string;
}

El argumento y tiene tipo string

def_val espera 'a' | 'b' | 'c' como claves. Esto significa que TypeScript solo te permite usar estas claves con def_val. Dado que el tipo string es mucho más amplio que 'a' | 'b' | 'c', estás obteniendo un error.

y:string significa que te permite pasar la propiedad foo y def_val['foo'] no es seguro ya que foo no existe en def_val.

Para solucionarlo, debes proporcionar un tipo explícito para def_val:

const def_val: Record<string, string> = { a: "debug", b: "info", c: "warning" };

function work(y: string) {
    let x = def_val[y] || def_val.a // ok
}

SI no se te permite usar un tipo explícito en def_val, puedes proporcionar def_val como un argumento para work:

const def_val = { a: "debug", b: "info", c: "warning" };

function work<Def extends Record<string, string>>(def: Def, y: string) {
    let x = def[y] || def.a
}
work(def_val, 'foo') // ok

También puedes usar un guardia de tipo personalizado:

const def_val = { a: "debug", b: "info", c: "warning" };

const isValidKey = (key: string): key is keyof typeof def_val =>
    /a|b|c/.test(key)

const work = (y: string) => isValidKey(y) ? def_val[y] : def_val.a

work('foo') // ok

P.D. Aquí puedes encontrar documentación sobre el uso de tipos de utilidad incorporados, como Record, Partial, etc ...