类型脚本:在类型'{“ A”:string;上未找到参数类型为'string'的索引签名。}

onT*_*net 24 javascript typescript

我有一些原始的javascript代码,需要输入字符串,将字符串拆分为字符,然后将这些字符与对象上的键匹配。

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
Run Code Online (Sandbox Code Playgroud)

这按预期工作。我现在想将其转换为打字稿。

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
Run Code Online (Sandbox Code Playgroud)

但我收到以下错误。

元素隐式地具有“ any”类型,因为类型'string'的表达式不能用于索引类型'{“ A”:string; }'。在类型>'{“ A”:string;上找不到带有参数'string'的索引签名。}'。ts(7053)

我以为问题是我需要我的对象键是一个字符串。但是将它们转换为字符串不起作用。

DNATranscriber = {
       "G":"C",
       "C": "G",
       "T": "A",
       "A": "U"
    }
Run Code Online (Sandbox Code Playgroud)

我对此很困惑。它说我的对象上不存在带有字符串类型的索引签名。但是我敢肯定。我究竟做错了什么?

编辑-我通过为DNATranscriber对象提供任何类型的对象来解决此问题。

DNATranscriber: any = {
    "G":"C",
    "C":"G",
    "T":"A",
    "A":"U"
}
Run Code Online (Sandbox Code Playgroud)

小智 46

在你的params你必须定义keyOf Object.

interface User {
    name: string
    age: number 
}

const user: User = {
    name: "someone",
    age: 20
}

function getValue(key: keyof User) {
    return user[key]
}
Run Code Online (Sandbox Code Playgroud)


小智 39

这是我为解决相关问题所做的工作

interface Map {
  [key: string]: string | undefined
}

const HUMAN_MAP: Map = {
  draft: "Draft",
}

export const human = (str: string) => HUMAN_MAP[str] || str

Run Code Online (Sandbox Code Playgroud)


Leo*_*uez 32

另外,您可以执行以下操作:

(this.DNATranscriber as any)[character];
Run Code Online (Sandbox Code Playgroud)

  • 明确的“DNA”类型不是一个坏主意,但是“this.DNATranscriber”不会像“DNATranscriber: DNA”那样声明,从而使“cast”变得多余吗? (11认同)
  • 嘿,我刚刚做了你在编辑版本中所说的。但仍然出现错误 (6认同)

Ale*_*kay 17

不要使用任何,使用泛型

// 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];
Run Code Online (Sandbox Code Playgroud)

不好 - 错误的原因是object默认情况下类型只是一个空对象。因此不可能使用string类型来索引{}

更好 - 错误消失的原因是因为现在我们告诉编译器obj参数将是字符串/值 ( string/any) 对的集合。但是,我们正在使用该any类型,因此我们可以做得更好。

最佳 -T扩展空对象。U扩展T. 因此U将始终存在于T,因此它可以用作查找值。

这是一个完整的例子:

我已经切换了泛型的顺序(U extends keyof T现在在之前T extends object)以强调泛型的顺序并不重要,您应该选择一个对您的函数最有意义的顺序。

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'
Run Code Online (Sandbox Code Playgroud)

替代语法

const getKeyValue = <T, K extends keyof T>(obj: T, key: K): T[K] => obj[key];
Run Code Online (Sandbox Code Playgroud)


Flá*_*les 14

您有两个简单且惯用的 Typescript 选项:

  1. 使用索引类型
DNATranscriber: { [char: string]: string } = {
  G: "C",
  C: "G",
  T: "A",
  A: "U",
};
Run Code Online (Sandbox Code Playgroud)

这是错误消息所谈论的索引签名。参考

  1. 键入每个属性:
DNATranscriber: { G: string; C: string; T: string; A: string } = {
  G: "C",
  C: "G",
  T: "A",
  A: "U",
};
Run Code Online (Sandbox Code Playgroud)


Alu*_*dad 12

您可以通过验证输入来纠正错误,无论如何,这都是您应做的事情。

以下类型通过类型保护验证正确进行类型检查

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;
}
Run Code Online (Sandbox Code Playgroud)

这是一个更惯用的版本

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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们如何利用TypeScript字符串枚举来提高清晰度并获得更强的碱基对映射类型。更重要的是,请注意我们如何使用function。这个很重要!将JavaScript转换为TypeScript与类无关,而与静态类型有关。

更新

从TypeScript 3.7开始,我们可以更富有表现力地编写此代码,使用断言签名将输入验证及其类型含义之间的对应关系形式化。

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;
}
Run Code Online (Sandbox Code Playgroud)

您可以在TypeScript 3.7发行说明中阅读有关断言签名的更多信息。

  • 作为替代方案,是否可以向“DNATranscriber”添加索引签名?由于错误显示“Typescript:在类型 '{ “A”: string; }”上找不到带有类型 'string' 参数的索引签名`,这意味着有一种方法可以添加类型 ' 的索引签名细绳'。这可以做到吗? (2认同)

小智 11

例如,您可以使用记录。

let DNATranscriber: Record<string, string> = {};
Run Code Online (Sandbox Code Playgroud)

  • 另一种类型可以是“let DNATranscriber: { [key: string]: string } = {};” (7认同)

小智 10

这将消除错误并且是类型安全的:

this.DNATranscriber[character as keyof typeof DNATranscriber]
Run Code Online (Sandbox Code Playgroud)

  • 这不是类型安全的。如果“character”具有编译时无法知道的动态值,则不能保证它始终是“keyof typeof DNATranscriber”类型。此处使用带有“as”的类型断言会引入类型安全错误。 (4认同)

Mat*_*ijs 9

我在我的getClass函数中解决了类似的问题,如下所示:

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];
}
Run Code Online (Sandbox Code Playgroud)

classes用我的联合类型输入我的const 使打字稿很高兴,这对我来说很有意义。


小智 7

const Translator : { [key: string]: string } = {
  G: "C",
  C: "G",
  T: "A",
  A: "U"
 }
 
 export function toRna(DNA:string) {

   const Translate = [...DNA];
   let Values = Translate.map((dna) => Translator[dna])
   if (Validate(Values)) {return Values.join('')}
 }

export function Validate(Values:string[]) : Boolean{
 if (Values.join('') === "" || Values.join('').length !== Values.length) throw Error('Invalid input DNA.');
 return true
}
Run Code Online (Sandbox Code Playgroud)

  • 通过额外的支持信息可以改进您的答案。请[编辑]添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以[在帮助中心](/help/how-to-answer)找到有关如何写出好的答案的更多信息。 (2认同)

小智 5

通过这样做解决了类似的问题:

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]
Run Code Online (Sandbox Code Playgroud)

  • 您可以添加关于这段代码的作用的解释吗? (2认同)