Tengo un código JavaScript de vanilla que toma una entrada de cadena, divide la cadena en caracteres y luego hace coincidir esos caracteres con una clave en un objeto.
DNATranscriber = {
"G":"C",
"C": "G",
"T": "A",
"A": "U"
}
function toRna(sequence){
const sequenceArray = [...sequence];
const transcriptionArray = sequenceArray.map(character =>{
return this.DNATranscriber[character];
});
return transcriptionArray.join("");
}
console.log(toRna("ACGTGGTCTTAA")); //Returns UGCACCAGAAUU
Esto funciona como se esperaba. Ahora me gustaría convertir esto a mecanografiado.
class Transcriptor {
DNATranscriber = {
G:"C",
C: "G",
T: "A",
A: "U"
}
toRna(sequence: string) {
const sequenceArray = [...sequence];
const transcriptionArray = sequenceArray.map(character =>{
return this.DNATranscriber[character];
});
}
}
export default Transcriptor
Pero recibo el siguiente error.
El elemento tiene implícitamente un tipo 'cualquier' porque la expresión del tipo 'cadena'> no se puede usar para indexar el tipo '{"A": cadena; } '. No se encontró ninguna firma de índice con un parámetro de tipo 'cadena' en el tipo> '{"A": cadena; } '. ts (7053)
Pensé que el problema era que necesitaba que mi clave de objeto fuera una cadena. Pero convertirlos en cadenas no funcionó.
DNATranscriber = {
"G":"C",
"C": "G",
"T": "A",
"A": "U"
}
Estoy bastante confundido por esto. Dice que no existe una firma de índice con un tipo de cadena en mi objeto. Pero estoy seguro de que sí. ¿Qué estoy haciendo mal?
Editar: resolví esto dando al objeto DNATranscriber un tipo de any.
DNATranscriber: any = {
"G":"C",
"C":"G",
"T":"A",
"A":"U"
}
fuente
toRna
any
y lo solucionará, de la misma manera que sacar la batería de un detector de humo soluciona un posible incendio.Respuestas:
Puede corregir los errores validando su entrada, que es algo que debe hacer independientemente, por supuesto.
El siguiente tipo verifica correctamente, a través de validaciones de protección de tipo
const DNATranscriber = { G: 'C', C: 'G', T: 'A', A: 'U' }; export default class Transcriptor { toRna(sequence: string) { const sequenceArray = [...sequence]; if (!isValidSequence(sequenceArray)) { throw Error('invalid sequence'); } const transcribedRNA = sequenceArray.map(codon => DNATranscriber[codon]); return transcribedRNA; } } function isValidSequence(codons: string[]): codons is Array<keyof typeof DNATranscriber> { return codons.every(isValidCodon); } function isValidCodon(value: string): value is keyof typeof DNATranscriber { return value in DNATranscriber; }
Aquí hay una versión más idiomática.
enum DNATranscriber { G = 'C', C = 'G', T = 'A', A = 'U' } export default function toRna(sequence: string) { const sequenceArray = [...sequence]; if (!isValidSequence(sequenceArray)) { throw Error('invalid sequence'); } const transcribedRNA = sequenceArray.map(codon => DNATranscriber[codon]); return transcribedRNA; } function isValidSequence(values: string[]): codons is Array<keyof typeof DNATranscriber> { return values.every(isValidCodon); } function isValidCodon(value: string): value is keyof typeof DNATranscriber { return value in DNATranscriber; }
Observe cómo aprovechamos una enumeración de cadenas de TypeScript para mejorar la claridad y obtener una escritura más sólida de las asignaciones de pares de bases. Más importante aún, observe cómo usamos un
function
. ¡Esto es importante! La conversión de JavaScript a TypeScript no tiene nada que ver con las clases, tiene que ver con los tipos estáticos.Actualización :
Desde TypeScript 3.7, podemos escribir esto de manera más expresiva, formalizando la correspondencia entre la validación de entrada y su implicación de tipo utilizando firmas de aserción .
enum DNATranscriber { G = 'C', C = 'G', T = 'A', A = 'U' } export default function toRna(sequence: string) { const sequenceArray = [...sequence]; validateSequence(sequenceArray); const transcribedRNA = sequenceArray.map(codon => DNATranscriber[codon]); return transcribedRNA; } function validateSequence(values: string[]): asserts codons is Array<keyof typeof DNATranscriber> { if (!values.every(isValidCodon)) { throw Error('invalid sequence'); } } function isValidCodon(value: string): value is keyof typeof DNATranscriber { return value in DNATranscriber; }
Puede leer más sobre las firmas de aserción en las notas de la versión de TypeScript 3.7 .
fuente
DNATranscriber
? Como dice el error"Typescript: No index signature with a parameter of type 'string' was found on type '{ “A”: string; }"
, implica que hay una manera de agregar una firma de índice de tipo 'cadena'. Se puede hacer esto?validateSequence ...:
escribe,codons
pero el nombre del parámetro esvalues
. Normalmente no es un problema, ya hay suficientes niveles de indirección ...Además, puedes hacer esto:
(this.DNATranscriber as any)[character];
Editar.
Se recomienda ALTAMENTE que lances el objeto con el tipo adecuado en lugar de
any
. Lanzar un objeto comoany
solo le ayuda a evitar errores de tipo al compilar mecanografiado, pero no le ayuda a mantener su código seguro.P.ej
interface DNA { G:"C", C: "G", T: "A", A: "U" }
Y luego lo lanzas así:
(this.DNATranscriber as DNA)[character];
fuente
DNA
tipo explícito no es una mala idea, pero ¿nothis.DNATranscriber
se declararía entonces como siDNATranscriber: DNA
el "elenco" fuera redundante?Esto fue lo que hice para resolver mi problema relacionado
interface Map { [key: string]: string | undefined } const HUMAN_MAP: Map = { draft: "Draft", } export const human = (str: string) => HUMAN_MAP[str] || str
fuente
No use ninguno, use genéricos
// bad const _getKeyValue = (key: string) => (obj: object) => obj[key]; // better const _getKeyValue_ = (key: string) => (obj: Record<string, any>) => obj[key]; // best const getKeyValue = <T extends object, U extends keyof T>(key: U) => (obj: T) => obj[key];
Malo: el motivo del error es que el
object
tipo es solo un objeto vacío de forma predeterminada. Por lo tanto, no es posible utilizar unstring
tipo para indexar{}
.Mejor: la razón por la que el error desaparece es porque ahora le estamos diciendo al compilador que el
obj
argumento será una colección destring/any
pares cadena / valor ( ). Sin embargo, estamos usando elany
tipo, por lo que podemos hacerlo mejor.Mejor:
T
extiende el objeto vacío.U
extiende las claves deT
. PorU
lo tanto , siempre existiráT
, por lo que se puede utilizar como valor de búsqueda.Aquí hay un ejemplo completo:
Cambié el orden de los genéricos (
U extends keyof T
ahora viene antesT extends object
) para resaltar que el orden de los genéricos no es importante y debe seleccionar un orden que tenga más sentido para su función.const getKeyValue = <U extends keyof T, T extends object>(key: U) => (obj: T) => obj[key]; interface User { name: string; age: number; } const user: User = { name: "John Smith", age: 20 }; const getUserName = getKeyValue<keyof User, User>("name")(user); // => 'John Smith'
Sintaxis alternativa
const getKeyValue = <T, K extends keyof T>(obj: T, key: K): T[K] => obj[key];
fuente
Resolví un problema similar en mi
getClass
función como este:import { ApiGateway } from './api-gateway.class'; import { AppSync } from './app-sync.class'; import { Cognito } from './cognito.class'; export type stackInstances = typeof ApiGateway | typeof AppSync | typeof Cognito export const classes = { ApiGateway, AppSync, Cognito } as { [key: string]: stackInstances }; export function getClass(name: string) { return classes[name]; }
Escribir mi
classes
constante con mi tipo de unión hizo feliz a la mecanografía y tiene sentido para mí.fuente
Tienes dos opciones con TypeScript simple e idiomático:
DNATranscriber: { [char: string]: string } = { G: "C", C: "G", T: "A", A: "U", };
Esta es la firma de índice de la que habla el mensaje de error. Referencia
DNATranscriber: { G: string; C: string; T: string; A: string } = { G: "C", C: "G", T: "A", A: "U", };
fuente
Me metí con esto por un tiempo. Aquí estaba mi escenario:
Tengo dos tipos, métricas1 y métricas2, cada uno con propiedades diferentes:
type metrics1 = { a: number; b: number; c: number; } type metrics2 = { d: number; e: number; f: number; }
En un punto de mi código, creé un objeto que es la intersección de estos dos tipos porque este objeto contendrá todas sus propiedades:
const myMetrics: metrics1 & metrics2 = { a: 10, b: 20, c: 30, d: 40, e: 50, f: 60 };
Ahora, necesito hacer referencia dinámicamente a las propiedades de ese objeto. Aquí es donde nos encontramos con errores de firma de índice. Parte del problema se puede desglosar en función de la verificación en tiempo de compilación y la verificación en tiempo de ejecución . Si hago referencia al objeto usando una constante , no veré ese error porque TypeScript puede verificar si la propiedad existe durante el tiempo de compilación:
const myKey = 'a'; console.log(myMetrics[myKey]); // No issues, TypeScript has validated it exists
Sin embargo, si estoy usando una variable dinámica (por ejemplo, let ), TypeScript no podrá verificar si la propiedad existe durante el tiempo de compilación y requerirá ayuda adicional durante el tiempo de ejecución. Ahí es donde entra en juego el siguiente tipo de protección:
function isValidMetric(prop: string, obj: metrics1 & metrics2): prop is keyof (metrics1 & metrics2) { return prop in obj; }
Esto se lee como, "Si el obj tiene la propiedad prop, entonces déjele saber a TypeScript que la prop existe en la intersección de metrics1 y metrics2". Nota : asegúrese de rodear metrics1 y metrics2 entre paréntesis después de keyof como se muestra arriba, o terminará con una intersección entre las claves de metrics1 y el tipo de metrics2 (no sus claves).
Ahora, puedo usar Typeguard y acceder de forma segura a mi objeto durante el tiempo de ejecución:
let myKey:string = ''; myKey = 'a'; if (isValidMetric(myKey, myMetrics)) { console.log(myMetrics[myKey]); }
fuente
Para aquellos que buscan en Google:
lo más probable es que su error deba leerse como:
Resolví un problema de escritura similar con un código como este:
const stringBasedKey = `SomeCustomString${someVar}` as keyof typeof YourTypeHere;
Este problema me ayudó a conocer el significado real del error.
fuente
Para cualquiera que tenga problemas con casos similares
No index signature with a parameter of type 'string' was found on type X
tratando de usarlo con objetos simples ( usados como dictados ) como:
DNATranscriber = { G:"C", C: "G", T: "A", A: "U" }
e intentar acceder dinámicamente al valor de una clave calculada como:
const key = getFirstType(dnaChain); const result = DNATranscriber[key];
y se enfrentó al error como se muestra arriba, puede usar el operador keyof e intentar algo como
const key = getFirstType(dnaChain) as keyof typeof DNATranscriber;
ciertamente necesitará un guardia en el
result
pero si parece más intuitivo que algunos tipos personalizados de magia, está bien.fuente
Esto eliminará el error y es seguro de tipos:
this.DNATranscriber[character as keyof typeof DNATranscriber]
fuente
Aquí está el ejemplo de función recortar tipo genérico de objeto de matriz
const trimArrayObject = <T>(items: T[]) => { items.forEach(function (o) { for (let [key, value] of Object.entries(o)) { const keyName = <keyof typeof o>key; if (Array.isArray(value)) { trimArrayObject(value); } else if (typeof o[keyName] === "string") { o[keyName] = value.trim(); } } }); };
fuente
Problema similar resuelto haciendo esto:
export interface IItem extends Record<string, any> { itemId: string; price: number; } const item: IItem = { itemId: 'someId', price: 200 }; const fieldId = 'someid'; // gives you no errors and proper typing item[fieldId]
fuente