React TypeScript:映射数组并从具有共享键的对象插入值

IT技术 reactjs typescript
2021-05-14 05:17:10

在 regualr javascript 我可以做...

var array1 = ['one', 'two', 'three', 'four'];
var object = {
  one: 'apple',
  two: 'orange',
  three: 'peach',
  four: 'kiwi',
}

const map1 = array1.map(x => `${object[x]}`);

console.log(map1); // ["apple", "orange", "peach", "kiwi"]

但是为了与 TypeScript 做出react,我想在 JSX 中做类似的事情

<ul>
   { state.array1.map( (arrayItem:string, index:number) => (<li key={index} >{state.object[arrayItem]}</li>)) }
</ul>

类型脚本警告是:

元素隐式具有 'any' 类型,因为类型 'any' 的表达式不能用于索引类型 '{ one: string; 二:字符串;三:字符串;四:字符串;

这就是我声明对象的方式

const object: {
    one: string;
    two: string;
    three: string;
    four: string;
}

当我将鼠标悬停在数组上时,它显示为 (property) array1: never[]

当我保存 array1 以说明它看起来像

 const [state, setState] = useState({ array1: []}); 
2个回答

问题是object只有键one, two,threefour

您稍微误读了警告。这里实际上有两件事,第一件事是

元素隐式具有 'any' 类型,因为类型 'string' 的表达式不能用于索引类型 '{ one: string; 二:字符串;三:字符串;四:字符串;}'。

这只是警告你object[x]不能保证给你任何当前的键one, two, three, or four,所以无论它获取什么都将被假定为any类型。这基本上涵盖了这种情况object["five"]——因为 TS 不知道这个属性的存在,它无法猜测它的类型——它可能是一个数字,或者一个字符串,或者只是undefined.

在类型 '{ one: string; 二:字符串;三:字符串;四:字符串;}'。

这就是阻止你的原因。同样,TS 只知道属性onetwothreefour,但是它无法知道您的数组仅包含这些属性当您没有明确说明数组包含什么时,它会尝试推断最常见的类型,在这种情况下是string. 而且,由于一个字符串不保证任何的onetwothree,和four(例如,它可能是five),然后TS不能保证你做什么是安全的。

您可以明确地说您的数组仅包含作为可行键的变量:

var array1: Array<'one' | 'two' | 'three'| 'four'> = ['one', 'two', 'three', 'four'];
var object = {
  one: 'apple',
  two: 'orange',
  three: 'peach',
  four: 'kiwi',
}

const map1 = array1.map(x => `${object[x]}`);

console.log(map1);

检查 TypeScript Playground

此外,如果您正式声明object's 类型是什么,您可以使用keyof而不是手动列出所有键:

interface MyObject {
  one: string;
  two: string;
  three: string;
  four: string;
}

var array1: Array<keyof MyObject> = ['one', 'two', 'three', 'four'];

var object: MyObject = {
  one: 'apple',
  two: 'orange',
  three: 'peach',
  four: 'kiwi',
}

const map1 = array1.map(x => `${object[x]}`);

console.log(map1);

检查 TypeScript Playground

尽管您可能会更非正式一些并且不为object. 这将导致以下代码,它将检查推断的类型object什么,然后创建一个包含所有键的数组:

var array1: Array<keyof typeof object> = ['one', 'two', 'three', 'four'];

var object = {
  one: 'apple',
  two: 'orange',
  three: 'peach',
  four: 'kiwi',
}

const map1 = array1.map(x => `${object[x]}`);

console.log(map1);

检查 TypeScript Playground

您最好的选择是第二个和第三个。第一个实际上只是为了强调为什么它不起作用。keyof'one' | 'two' | 'three'| 'four'此代码中的可互换,但它的好处是如果object的定义发生更改,则无需更新多个位置

问题是它array1被认为是一个字符串数组 ( string[]) 但object不接受所有字符串作为键。

要么你需要

  • 定义array1为所有可能键的数组
type PossibleKey = 'one' | 'two' | 'three' | 'four';
var array1: PossibleKey[] = ['one', 'two', 'three', 'four'];
var object = {
  one: 'apple',
  two: 'orange',
  three: 'peach',
  four: 'kiwi',
}
const map1 = array1.map(x => `${object[x]}`);
  • makeobject接受所有字符串作为键
var array1 = ['one', 'two', 'three', 'four'];
var object: Record<string, string> = {
  one: 'apple',
  two: 'orange',
  three: 'peach',
  four: 'kiwi',
}
const map1 = array1.map(x => `${object[x]}`);