如何获取泛型类型的属性?

21

我有一个抽象类,在其中的方法中,我传递了一个泛型类型的项。接下来,我需要获取此项的属性,如何正确地进行操作?

export abstract class BaseService<T> {
    ...
    public saveItem(item: T) {
        ...
        if (item.id <=== here I got error ) {
        }
        ...
    }

    export class ClusterItem {
        id: number;
        ...
     }

    export class ClustersService extends BaseService<ClusterItem> {
        ...
    }

1
你可以使用类型保护来在尝试访问某些属性或通过方括号表示法item['id']访问之前检查类型。 - Alexander Staroselsky
4
也许可以使用T extends {id: number}这个语法来限制泛型类型为具有该属性的东西。 - jonrsharpe
3个回答

33
您的代码假设每个与类一起使用的类型T都可能具有一个id属性。
正如Jon Sharpe在他对您的问题的评论中指出的那样,正确的方法是将此假设声明为类型约束,使其明确并已知于类型检查器。
实现此目标的方法是在泛型类型参数上使用类型约束语法。
例如,您可以编写:
export interface MayHaveId {
  id?: number; // you can use any type, number is just an example
}

export abstract class BaseService<T extends MayHaveId> {
  saveItem(item: T) {
    if (item.id !== undefined) {
      console.log(item.id);
    }
  }
} 

在这里,我们定义了一个接口来使代码更易读,但类型字面量同样适用。

请注意,id属性是可选的,因为您的逻辑不要求它具有值。

如果您只打算将基类与具有id的类型参数一起使用,则应使该属性为必需。这将使代码更易于理解,并通过确保它仅与此类类型一起使用而在编译时捕获更多错误。

Shahbaaz在评论中提到了动态属性。

我们可以使用参数化泛型类型来定义带有动态属性的类型。

type WithProperty<K extends string, V = {}> = {
  [P in K]: V
}

我们可以使用这种类型。
function withProperty<T, K extends string, V> (x: T, properties: WithProperty<K, V>) {
  return Object.assign(x, properties);
}

如果要求在对象中发送属性名称,即属性名称是动态的,该怎么办? - Shahbaaz
1
@Shahbaaz 有点跑题了,但我添加了一个例子。 - Aluan Haddad

0
只需像方法一样扩展泛型类型参数即可:
const fn = <T extends { id: T['id']}>(items: T[]) => ...

一个使用示例:

const ids = <T extends { id: T['id']}>(items: T[]) => items.map((item) => item.id);

const numbers = ids([{ id: 1 }, { id: 2 }, { id: 3 }]);
const strings = ids([{ id: 'a' }, { id: 'b' }, { id: 'c' }]);

// type check error:
const typeError = ids<{ id: number }>([{ id: "46100709" }]);

-2

这将无法与 TypeScript 一起工作。 - DeltaTango
@DeltaTango,它可以与TypeScript一起使用。它只是解决了一个不同的问题,JavaScript和TypeScript代码也经常处理这个问题。 - Aluan Haddad
不,它不会。错误将继续存在,因为接口/类型不包含它。 - DeltaTango

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接