Typescript: No index signature with a parameter of type 'string' was found on type '{ "A": string; }
I have some vanilla javascript code that takes a string input, splits the string into characters, and then matches those characters to a key on an object.
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
This works as expected. I'd now like to convert this to typescript.
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
But I'm getting the following error.
Element implicitly has an 'any' type because expression of type 'string' >can't be used to index type '{ "A": string; }'. No index signature with a parameter of type 'string' was found on type >'{ "A": string; }'.ts(7053)
I thought that the issue was that I needed my object key to be a string. But converting them to strings didn't work.
DNATranscriber = {
"G":"C",
"C": "G",
"T": "A",
"A": "U"
}
I'm quite confused by this. It says that no index signature with a type of string exists on my object. But I'm sure that it does. What am I doing wrong?
Edit - I solved this by giving the DNATranscriber object a type of any.
DNATranscriber: any = {
"G":"C",
"C":"G",
"T":"A",
"A":"U"
}
Also, you can do this:
(this.DNATranscriber as any)[character];
Edit.
It's HIGHLY recommended that you cast the object with the proper type instead of any
. Casting an object as any
only help you to avoid type errors when compiling typescript but it doesn't help you to keep your code type-safe.
E.g.
interface DNA {
G: "C",
C: "G",
T: "A",
A: "U"
}
And then you cast it like this:
(this.DNATranscriber as DNA)[character];
You can fix the errors by validating your input, which is something you should do regardless of course.
The following typechecks correctly, via type guarding validations
const DNATranscriber = {
G: 'C',
C: 'G',
T: 'A',
A: 'U'
};
export default class Transcriptor {
toRna(dna: string) {
const codons = [...dna];
if (!isValidSequence(codons)) {
throw Error('invalid sequence');
}
const transcribedRNA = codons.map(codon => DNATranscriber[codon]);
return transcribedRNA;
}
}
function isValidSequence(values: string[]): values is Array<keyof typeof DNATranscriber> {
return values.every(isValidCodon);
}
function isValidCodon(value: string): value is keyof typeof DNATranscriber {
return value in DNATranscriber;
}
It is worth mentioning that you seem to be under the misapprehention that converting JavaScript to TypeScript involves using classes.
In the following, more idiomatic version, we leverage TypeScript to improve clarity and gain stronger typing of base pair mappings without changing the implementation. We use a function
, just like the original, because it makes sense. This is important! Converting JavaScript to TypeScript has nothing to do with classes, it has to do with static types.
const DNATranscriber = {
G: 'C',
C: 'G',
T: 'A',
A: 'U'
};
export default function toRna(dna: string) {
const codons = [...dna];
if (!isValidSequence(codons)) {
throw Error('invalid sequence');
}
const transcribedRNA = codons.map(codon => DNATranscriber[codon]);
return transcribedRNA;
}
function isValidSequence(values: string[]): values is Array<keyof typeof DNATranscriber> {
return values.every(isValidCodon);
}
function isValidCodon(value: string): value is keyof typeof DNATranscriber {
return value in DNATranscriber;
}
Update:
Since TypeScript 3.7, we can write this more expressively, formalizing the correspondence between input validation and its type implication using assertion signatures.
const DNATranscriber = {
G: 'C',
C: 'G',
T: 'A',
A: 'U'
} as const;
type DNACodon = keyof typeof DNATranscriber;
type RNACodon = typeof DNATranscriber[DNACodon];
export default function toRna(dna: string): RNACodon[] {
const codons = [...dna];
validateSequence(codons);
const transcribedRNA = codons.map(codon => DNATranscriber[codon]);
return transcribedRNA;
}
function validateSequence(values: string[]): asserts values is DNACodon[] {
if (!values.every(isValidCodon)) {
throw Error('invalid sequence');
}
}
function isValidCodon(value: string): value is DNACodon {
return value in DNATranscriber;
}
You can read more about assertion signatures in the TypeScript 3.7 release notes.