Typoskript: Für Typ '{“A”: string wurde keine Indexsignatur mit einem Parameter vom Typ' string 'gefunden. }}

79

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"
}
im Internet
quelle
Es ist nicht die Antwort, aber Sie haben vergessen, den Wert vontoRna
Reza
Was ist Ihre Typoskript-Version? Ich erhalte keine Fehler stackblitz.com/edit/angular-kupcve `
Reza
Es ist Version "2.5.3"
onTheInternet
44
Sicher, geben Sie etwas ein wie anyund es wird es beheben, genauso wie das Herausnehmen der Batterie aus einem Rauchmelder ein potenzielles Feuer behebt.
Jcalz
1
Autsch, du hast mich direkt in die Metapher getroffen. Wie auch immer, so würde ich es machen
jcalz

Antworten:

45

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 .

Aluan Haddad
quelle
1
Ist es alternativ möglich, eine Indexsignatur hinzuzufügen 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?
Cameron Hudson
Ja, Sie könnten das tun, aber dann wäre der Code nicht typsicher oder ausdrucksstark, wie es die Frage beabsichtigte. Es gibt einen Grund, warum er es nicht so geschrieben hat, einen guten Grund.
Aluan Haddad
69

Sie können dies auch tun:

(this.DNATranscriber as any)[character];

Bearbeiten.

Es wird dringend empfohlen, das Objekt stattdessen mit dem richtigen Typ umzuwandelnany . Das Umwandeln eines Objekts anyhilft 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];
Leonardo Emilio Dominguez
quelle
1
Hey, ich habe gerade getan, was du in deiner Bearbeitungsversion gesagt hast. aber immer noch Fehler
Archsx
1
Ein expliziter DNATyp ist keine schlechte Idee, würde this.DNATranscriberdann aber nicht als DNATranscriber: DNAüberflüssig erklärt werden?
Aluan Haddad
11

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

Manoel Quirino Neto
quelle
8

Ich habe ein ähnliches Problem in meiner getClassFunktion 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 classesKonstante mit meinem Union-Typ machte das Typoskript glücklich und es macht für mich Sinn.

Mattijs
quelle
7

Sie haben zwei Möglichkeiten mit einfachem und idiomatischem Typoskript:

  1. Verwenden Sie den Indextyp
DNATranscriber: { [char: string]: string } = {
  G: "C",
  C: "G",
  T: "A",
  A: "U",
};

Dies ist die Indexsignatur, über die die Fehlermeldung spricht. Referenz

  1. Geben Sie jede Eigenschaft ein:
DNATranscriber: { G: string; C: string; T: string; A: string } = {
  G: "C",
  C: "G",
  T: "A",
  A: "U",
};
Flávio Teixeira Vertrieb
quelle
7

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 objectTyp standardmäßig nur ein leeres Objekt ist. Daher ist es nicht möglich, einen stringTyp zum Indizieren zu verwenden {}.

Besser - der Grund, warum der Fehler verschwindet, ist, dass wir dem Compiler jetzt mitteilen, dass das objArgument eine Sammlung von Zeichenfolgen / Wert ( string/any) -Paaren sein wird. Wir verwenden jedoch den anyTyp, damit wir es besser machen können.

Am besten - Terweitert leeres Objekt. Uerweitert die Tasten von T. Daher Uwird immer auf vorhanden sein T, daher kann es als Nachschlagewert verwendet werden.

Hier ist ein vollständiges Beispiel:

Ich habe die Reihenfolge der Generika geändert ( U extends keyof Tkommt jetzt vorher T 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];
Alex Mckay
quelle
Wie würde dies funktionieren, wenn der Benutzer einen anderen Schlüssel mit einer Schnittstelle wie der Typ hätte? Ich erhalte die Fehlermeldung, dass sie nicht 'Zeichenfolge' zugewiesen werden können.
Lockykeaney
Los
Alex Mckay
@AlexMckay Du bist ein Genie! Danke für die Antwort,
Avinash
Ich habe ein winziges npm-Paket mit dieser Funktion geschrieben, um diese Aufgabe für diejenigen zu vereinfachen, die neu in Typescript sind. Es ist 38 Bytes, sobald es minimiert ist, und enthält einen jsdoc-Kommentar. Wenn Sie also mit der Maus über die Funktion fahren, wird die obige Antwort angezeigt.
Alex Mckay
1

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]);
}
John Galt
quelle
0

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, resultaber wenn es intuitiver erscheint als einige benutzerdefinierte Arten von Magie, ist es in Ordnung.

Igneel64
quelle
0

Dies beseitigt den Fehler und ist typsicher:

this.DNATranscriber[character as keyof typeof DNATranscriber]
Almeno Soares
quelle
0

Für diejenigen, die Google:

Für den Typ ... wurde keine Indexsignatur mit einem Parameter vom Typ 'string' gefunden ...

Höchstwahrscheinlich sollte Ihr Fehler wie folgt lauten:

Wollten Sie einen spezifischeren Typ verwenden, wie z keyof Number statt string?

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.

Pavot
quelle