Ich habe einen Vanille-Javascript-Code, der eine Zeichenfolgeneingabe übernimmt, die Zeichenfolge in Zeichen aufteilt und diese Zeichen dann einem Schlüssel auf einem Objekt zuordnet.
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
Dies funktioniert wie erwartet. Ich möchte dies jetzt in Typoskript konvertieren.
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
Aber ich erhalte den folgenden Fehler.
Das Element hat implizit den Typ 'any', da der Ausdruck vom Typ 'string'> nicht zum Indizieren des Typs '{"A" verwendet werden kann: string; } '. Für Typ> '{"A": string wurde keine Indexsignatur mit einem Parameter vom Typ' string 'gefunden. } '. ts (7053)
Ich dachte, das Problem sei, dass ich meinen Objektschlüssel als Zeichenfolge benötige. Aber das Konvertieren in Strings hat nicht funktioniert.
DNATranscriber = {
"G":"C",
"C": "G",
"T": "A",
"A": "U"
}
Das verwirrt mich ziemlich. Es heißt, dass für mein Objekt keine Indexsignatur mit einem Zeichenfolgentyp vorhanden ist. Aber ich bin mir sicher, dass es so ist. Was mache ich falsch?
Bearbeiten - Ich habe dieses Problem gelöst, indem ich dem DNATranscriber-Objekt einen beliebigen Typ gegeben habe.
DNATranscriber: any = {
"G":"C",
"C":"G",
"T":"A",
"A":"U"
}
quelle
toRna
any
und es wird es beheben, genauso wie das Herausnehmen der Batterie aus einem Rauchmelder ein potenzielles Feuer behebt.Antworten:
Sie können die Fehler beheben, indem Sie Ihre Eingabe validieren. Dies sollten Sie unabhängig vom Kurs tun.
Die folgenden Typprüfungen werden über Typschutzprüfungen korrekt durchgeführt
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; }
Hier ist eine idiomatischere Version
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; }
Beachten Sie, wie wir eine TypeScript-Zeichenfolgenaufzählung nutzen, um die Übersichtlichkeit zu verbessern und die Typisierung von Basenpaarzuordnungen zu verbessern. Beachten Sie vor allem, wie wir a verwenden
function
. Das ist wichtig! Das Konvertieren von JavaScript in TypeScript hat nichts mit Klassen zu tun, sondern mit statischen Typen.Update :
Seit TypeScript 3.7 können wir dies aussagekräftiger schreiben und die Korrespondenz zwischen der Eingabevalidierung und ihrer Typimplikation mithilfe von Assertionssignaturen formalisieren .
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; }
Weitere Informationen zu Assertionssignaturen finden Sie in den Versionshinweisen zu TypeScript 3.7 .
quelle
DNATranscriber
? Da der Fehler besagt"Typescript: No index signature with a parameter of type 'string' was found on type '{ “A”: string; }"
, dass es eine Möglichkeit gibt, eine Indexsignatur vom Typ 'string' hinzuzufügen. Kann das gemacht werden?Sie können dies auch tun:
(this.DNATranscriber as any)[character];
Bearbeiten.
Es wird dringend empfohlen, das Objekt stattdessen mit dem richtigen Typ umzuwandeln
any
. Das Umwandeln eines Objektsany
hilft Ihnen nur, Tippfehler beim Kompilieren von Typoskript zu vermeiden, aber es hilft Ihnen nicht, Ihren Code typsicher zu halten.Z.B
interface DNA { G:"C", C: "G", T: "A", A: "U" }
Und dann wirfst du es so:
(this.DNATranscriber as DNA)[character];
quelle
DNA
Typ ist keine schlechte Idee, würdethis.DNATranscriber
dann aber nicht alsDNATranscriber: DNA
überflüssig erklärt werden?Dies war, was ich tat, um mein damit verbundenes Problem zu lösen
interface Map { [key: string]: string | undefined } const HUMAN_MAP: Map = { draft: "Draft", } export const human = (str: string) => HUMAN_MAP[str] || str
quelle
Ich habe ein ähnliches Problem in meiner
getClass
Funktion wie folgt gelöst :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]; }
Das Tippen meiner
classes
Konstante mit meinem Union-Typ machte das Typoskript glücklich und es macht für mich Sinn.quelle
Sie haben zwei Möglichkeiten mit einfachem und idiomatischem Typoskript:
DNATranscriber: { [char: string]: string } = { G: "C", C: "G", T: "A", A: "U", };
Dies ist die Indexsignatur, über die die Fehlermeldung spricht. Referenz
DNATranscriber: { G: string; C: string; T: string; A: string } = { G: "C", C: "G", T: "A", A: "U", };
quelle
Verwenden Sie keine, verwenden Sie Generika
// 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];
Schlecht - Der Grund für den Fehler ist, dass der
object
Typ standardmäßig nur ein leeres Objekt ist. Daher ist es nicht möglich, einenstring
Typ zum Indizieren zu verwenden{}
.Besser - der Grund, warum der Fehler verschwindet, ist, dass wir dem Compiler jetzt mitteilen, dass das
obj
Argument eine Sammlung von Zeichenfolgen / Wert (string/any
) -Paaren sein wird. Wir verwenden jedoch denany
Typ, damit wir es besser machen können.Am besten -
T
erweitert leeres Objekt.U
erweitert die Tasten vonT
. DaherU
wird immer auf vorhanden seinT
, daher kann es als Nachschlagewert verwendet werden.Hier ist ein vollständiges Beispiel:
Ich habe die Reihenfolge der Generika geändert (
U extends keyof T
kommt jetzt vorherT extends object
), um hervorzuheben, dass die Reihenfolge der Generika nicht wichtig ist und Sie eine Reihenfolge auswählen sollten, die für Ihre Funktion am sinnvollsten ist.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'
Alternative Syntax
const getKeyValue = <T, K extends keyof T>(obj: T, key: K): T[K] => obj[key];
quelle
Ich habe eine Weile damit rumgespielt. Hier war mein Szenario:
Ich habe zwei Typen, Metriken1 und Metriken2, die jeweils unterschiedliche Eigenschaften haben:
type metrics1 = { a: number; b: number; c: number; } type metrics2 = { d: number; e: number; f: number; }
An einem Punkt in meinem Code habe ich ein Objekt erstellt, das den Schnittpunkt dieser beiden Typen darstellt, da dieses Objekt alle seine Eigenschaften enthält:
const myMetrics: metrics1 & metrics2 = { a: 10, b: 20, c: 30, d: 40, e: 50, f: 60 };
Jetzt muss ich dynamisch auf die Eigenschaften dieses Objekts verweisen. Hier stoßen wir auf Indexsignaturfehler. Ein Teil des Problems kann anhand der Überprüfung der Kompilierungszeit und der Laufzeit aufgeschlüsselt werden . Wenn ich mit einer Konstante auf das Objekt verweise , wird dieser Fehler nicht angezeigt, da TypeScript prüfen kann, ob die Eigenschaft während der Kompilierungszeit vorhanden ist:
const myKey = 'a'; console.log(myMetrics[myKey]); // No issues, TypeScript has validated it exists
Wenn ich jedoch eine dynamische Variable verwende (z. B. let ), kann TypeScript nicht überprüfen, ob die Eigenschaft während der Kompilierungszeit vorhanden ist, und benötigt zur Laufzeit zusätzliche Hilfe. Hier kommt der folgende Typeguard ins Spiel:
function isValidMetric(prop: string, obj: metrics1 & metrics2): prop is keyof (metrics1 & metrics2) { return prop in obj; }
Dies lautet wie folgt : "Wenn das Objekt die Eigenschaft prop hat, teilen Sie TypeScript mit, dass prop im Schnittpunkt von Metriken1 und Metriken2 vorhanden ist." Hinweis : Stellen Sie sicher, dass Sie Metriken1 und Metriken2 wie oben gezeigt in Klammern nach keyof einschließen. Andernfalls wird ein Schnittpunkt zwischen den Schlüsseln von Metriken1 und dem Typ von Metriken2 (nicht den Schlüsseln) angezeigt.
Jetzt kann ich den Typeguard verwenden und zur Laufzeit sicher auf mein Objekt zugreifen:
let myKey:string = ''; myKey = 'a'; if (isValidMetric(myKey, myMetrics)) { console.log(myMetrics[myKey]); }
quelle
Für alle, die mit ähnlichen Fällen zu kämpfen haben
No index signature with a parameter of type 'string' was found on type X
versuchen, es mit einfachen Objekten ( als Diktate verwendet ) wie zu verwenden:
DNATranscriber = { G:"C", C: "G", T: "A", A: "U" }
und versuchen, dynamisch von einem berechneten Schlüssel auf den Wert zuzugreifen, wie:
const key = getFirstType(dnaChain); const result = DNATranscriber[key];
Wenn Sie wie oben gezeigt auf den Fehler gestoßen sind , können Sie den Operator keyof verwenden und so etwas wie versuchen
const key = getFirstType(dnaChain) as keyof typeof DNATranscriber;
Sicherlich brauchen Sie eine Wache an der,
result
aber wenn es intuitiver erscheint als einige benutzerdefinierte Arten von Magie, ist es in Ordnung.quelle
Dies beseitigt den Fehler und ist typsicher:
this.DNATranscriber[character as keyof typeof DNATranscriber]
quelle
Für diejenigen, die Google:
Höchstwahrscheinlich sollte Ihr Fehler wie folgt lauten:
Ich habe ein ähnliches Tippproblem mit Code wie diesem gelöst:
const stringBasedKey = `SomeCustomString${someVar}` as keyof typeof YourTypeHere;
Dieses Problem hat mir geholfen, die wahre Bedeutung des Fehlers zu erkennen.
quelle