我有一些原始的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
这按预期工作。我现在想将其转换为打字稿。
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
但是出现以下错误。
元素隐式具有'any'类型,因为类型'string'的表达式>不能用于索引类型'{“ A”:string; }'。 在类型>'{“ A”:string;上找不到参数类型为'string'的索引签名。 }'。ts(7053)
我认为问题是我需要我的对象密钥是一个字符串。但是将它们转换为字符串不起作用。
DNATranscriber = {
"G":"C",
"C": "G",
"T": "A",
"A": "U"
}
对此我感到很困惑。它说我的对象上不存在带有字符串类型的索引签名。但我敢肯定。我在做什么错了?
编辑-我为DNATranscriber对象提供了任意类型的对象。
DNATranscriber: any = {
"G":"C",
"C":"G",
"T":"A",
"A":"U"
}
答案 0 :(得分:15)
这就是我解决相关问题的方法
interface Map {
[key: string]: string | undefined
}
const HUMAN_MAP: Map = {
draft: "Draft",
}
export const human = (str: string) => HUMAN_MAP[str] || str
答案 1 :(得分:10)
不使用任何东西,使用泛型
// 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];
错误-错误的原因是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'
const getKeyValue = <T, K extends keyof T>(obj: T, key: K): T[K] => obj[key];
答案 2 :(得分:8)
我在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];
}
用我的联合体类型键入classes
常量会使打字稿感到高兴,这对我来说很有意义。
答案 3 :(得分:8)
您有两个简单且惯用的打字稿选项:
DNATranscriber: { [char: string]: string } = {
G: "C",
C: "G",
T: "A",
A: "U",
};
这是错误消息所讨论的索引签名。 Reference
DNATranscriber: { G: string; C: string; T: string; A: string } = {
G: "C",
C: "G",
T: "A",
A: "U",
};
答案 4 :(得分:3)
您可以通过验证输入来纠正错误,无论如何,您都应该这样做。
以下类型通过类型保护验证正确检查
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(codon: string): codon is keyof typeof DNATranscriber {
return codon in DNATranscriber;
}
这是更惯用的版本
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(codons: string[]): codons is Array<keyof typeof DNATranscriber> {
return codons.every(isValidCodon);
}
function isValidCodon(codon: string): codon is keyof typeof DNATranscriber {
return codon in DNATranscriber;
}
注意我们如何利用TypeScript字符串枚举来提高清晰度并获得更强的碱基对映射类型。更重要的是,请注意我们如何使用函数。这个很重要!将JS转换为TS与类无关,而与静态类型有关。
答案 5 :(得分:2)
此外,您可以执行以下操作:
(this.DNATranscriber as any)[character];
答案 6 :(得分:1)
我把这个弄乱了一段时间。这是我的情况:
我有两种类型,metrics1和metrics2,每种都有不同的属性:
type metrics1 = {
a: number;
b: number;
c: number;
}
type metrics2 = {
d: number;
e: number;
f: number;
}
在我的代码中,我创建了一个对象,这是这两种类型的交集,因为该对象将保留其所有属性:
const myMetrics: metrics1 & metrics2 = {
a: 10,
b: 20,
c: 30,
d: 40,
e: 50,
f: 60
};
现在,我需要动态引用该对象的属性。这是我们遇到索引签名错误的地方。可以根据编译时检查和运行时检查来解决部分问题。如果我使用 const 引用该对象,则不会看到该错误,因为TypeScript可以在编译时检查该属性是否存在:
const myKey = 'a';
console.log(myMetrics[myKey]); // No issues, TypeScript has validated it exists
但是,如果我使用的是动态变量(例如 let ),则TypeScript将无法在编译时检查该属性是否存在,并且在运行时需要其他帮助。这就是以下Typeguard出现的地方:
function isValidMetric(prop: string, obj: metrics1 & metrics2): prop is keyof (metrics1 & metrics2) {
return prop in obj;
}
读为“如果 obj 具有属性 prop ,则让TypeScript知道 prop 存在于metrics1和metrics2的交集中。” 注意:请确保如上所示,在关键字之后的括号内包含度量1和度量2,否则最终会导致度量1的键和度量2的类型之间出现交集(不是其键)。
现在,我可以使用Typeguard并在运行时安全地访问对象了:
let myKey:string = '';
myKey = 'a';
if (isValidMetric(myKey, myMetrics)) {
console.log(myMetrics[myKey]);
}
答案 7 :(得分:1)
对于那些使用Google的用户:
在类型...上未找到参数类型为“字符串”的索引签名。
您的错误很可能显示为:
您是要使用更具体的类型,例如
keyof Number
而不是string
?
我使用如下代码解决了类似的打字问题:
const stringBasedKey = `SomeCustomString${someVar}` as keyof typeof YourTypeHere;
This issue帮助我学习了错误的真正含义。
答案 8 :(得分:0)
适用于遇到类似案件的人
No index signature with a parameter of type 'string' was found on type X
尝试将其用于简单的对象(如dicts ):
DNATranscriber = {
G:"C",
C: "G",
T: "A",
A: "U"
}
,并尝试从计算出的键中动态访问值,例如:
const key = getFirstType(dnaChain);
const result = DNATranscriber[key];
,您遇到了上述错误,可以使用keyof operator并尝试类似的操作
const key = getFirstType(dnaChain) as keyof typeof DNATranscriber;
当然,您需要对result
保持警惕,但是如果它看起来比某些自定义类型魔术更直观,那就可以了。
答案 9 :(得分:0)
这将消除错误,并且是安全的:
this.DNATranscriber[character as keyof typeof DNATranscriber]
答案 10 :(得分:0)
这是函数示例修剪数组对象的通用类型
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();
}
}
});
};
答案 11 :(得分:0)
解决了类似的问题:
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]
答案 12 :(得分:0)
这里有一个不使用对象键的解决方案:
function toRna(value: string): string {
return value.split('').map(ch => 'CGAU'['GCTA'.indexOf(ch)]).join('');
}
console.log(toRna('ACGTGGTCTTAA'));
\\UGCACCAGAAUU
答案 13 :(得分:0)
你可以使用 type a return type 来获取,就像这样。
getAllProperties(SellRent: number) : Observable<IProperty[]>{
return this.http.get<IProperty[]>('data/properties.json').pipe(
map(data => {
const propertiesArray: Array<IProperty> = [];
for(const id in data){
if(data.hasOwnProperty(id) && data[id].SellRent === SellRent){
propertiesArray.push(data[id]);
}
}
return propertiesArray;
})
)
}
答案 14 :(得分:0)
在您的 params
上,您必须定义 keyOf Object
。
interface User {
name: string
age: number
}
const user: User = {
name: "someone",
age: 20
}
function getValue(key: keyof User) {
return user[key]
}