简体   繁体   English

使用 typescript generics 键入函数时出现问题

[英]Problems typing functions using typescript generics

Case #1情况1

I am getting error:我收到错误:

Property 'name' does not exist on type 'T'类型“T”上不存在属性“名称”

function test<T>(arr:Array<T>, item:T) {

const idxReplaced = arr.findIndex(element=> element.name === item.name)
  return {
     ...arr.slice(0, idxReplaced),
     ...arr.slice(idxReplaced+1)
  }

}

interface IItem {
  name: number
}


console.log(test<IItem>([{name:1},{name:3}], {name: 3}))

Case #2案例#2

I want to change every name property in object array according its name.我想根据其名称更改 object 数组中的每个名称属性。

I am getting errors:我收到错误:

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'ICurrentItem'元素隐式具有“any”类型,因为“any”类型的表达式不能用于索引类型“ICurrentItem”

and

Property 'name' does not exist on type 'IItem'.类型“IItem”上不存在属性“名称”。

interface IItem {
  user: string,
}
  
interface ICurrentItem {
  [key: string]: IItem
}

function test<IItem>(arr:Array<IItem>, item:IItem) {

return arr.reduce((acc:ICurrentItem,el:IItem)=> {
    acc[el.user] = item[el.user]
    return acc
  },{})
}   

console.log(test([{user:'info'},{user:'test'}], {user: 'some info'}))

You can test it here: Typescript Playground你可以在这里测试它: Typescript Playground

Case #1情况1

@kaya3's comment is correct. @kaya3 的评论是正确的。 Your function assumes that your array elements and your item variable (both type T ) will have a .name property.您的 function 假定您的数组元素和item变量(均为T类型)将具有.name属性。 So you must ensure that all possible types for T include at least a name .因此,您必须确保T的所有可能类型至少包含一个name

function test1<T extends { name: any }>(arr: Array<T>, item: T) {

  const idxReplaced = arr.findIndex(element => element.name === item.name)
  return [
    ...arr.slice(0, idxReplaced),
    ...arr.slice(idxReplaced + 1)
  ]
}

You don't need to set the generic here because it is inferred as <{name: number}> based on the arguments.您不需要在此处设置泛型,因为它根据 arguments 推断为<{name: number}>

console.log(test1([{ name: 1 }, { name: 3 }], { name: 3 }))

Case #2案例#2

function test<IItem>(arr:Array<IItem>, item:IItem) {

This right here shows a misunderstanding of generic type parameters.这在这里显示了对泛型类型参数的误解。 You can use any name for the generic type and <IItem> here is basically <T> with another name.您可以为泛型类型使用任何名称,这里的<IItem>基本上是带有另一个名称的<T> It is a local type variable that bears no relation to the interface IItem .它是一个与interface IItem的局部类型变量。

I suspect what you meant to do was something like this, where the generic type must extend {user: string} :我怀疑你的意思是这样的,泛型类型必须扩展{user: string}

function test2<T extends IItem>(arr: Array<T>, item: T) {

Or to not have it be generic at all, and simply add types to the arguments:或者根本不让它通用,只需将类型添加到 arguments:

function test2(arr: Array<IItem>, item: IItem) {

We are building an object acc where the key is a string from the item's user property and the value is an item .我们正在构建一个 object acc ,其中键是项目user属性的string ,值是item You've got that part typed correctly.您已经正确输入了该部分。 It's fine to access acc[el.user] because acc has a string index.访问acc[el.user]很好,因为acc有一个字符串索引。

But what are you trying to to do with item[el.user] ?但是你想用item[el.user]做什么? el.user is the username string and item is an IItem . el.user是用户名string ,而itemIItem It does not have a property that corresponds to the user value.它没有与user值对应的属性。

In your example:在您的示例中:

console.log(test2([{ user: 'info' }, { user: 'test' }], { user: 'some info' }))

You would be accessing ({ user: 'some info' }).info and ({ user: 'some info' }).test .您将访问({ user: 'some info' }).info({ user: 'some info' }).test Typescript is right to warn you that those don't exist. Typescript 是正确的警告您这些不存在。

I'm genuinely not sure what you are trying to achieve here.我真的不确定您要在这里实现什么。 If you meant to turn an array of items into an object keyed by the username then you don't need a second argument item for that.如果您打算将一组项目转换为由用户名键入的 object,那么您不需要第二个参数item That would be:那将是:

interface IItem {
  user: string,
}

interface ICurrentItem<T extends IItem> {
  [key: string]: T
}

function test2<T extends IItem>(arr: Array<T>) {

  return arr.reduce((acc: ICurrentItem<T>, el: T) => {
    acc[el.user] = el
    return acc
  }, {})
}

console.log(test2([{ user: 'info' }, { user: 'test' }]))

Typescript Playground Link Typescript 游乐场链接

edit: "I want to change every name property in object array according its name."编辑: “我想根据名称更改 object 数组中的每个名称属性。”

I think maybe you want map instead of reduce ?我想也许你想要map而不是reduce

This code replaces the user property of the array elements with the user property from item.user ("some info").此代码将数组元素的user属性替换为item.user中的用户属性(“一些信息”)。

function test<T extends IItem>(arr: Array<T>, item: T) {

  return arr.map(el => ({ ...el, user: item.user }));
}

console.log(test([{ user: 'info' }, { user: 'test' }], { user: 'some info' }))
// output: [{ "user": "some info" }, { "user": "some info" }] 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM