字符串类型的打字稿 T[keyof T]

Typescript T[keyof T] of type string

演示:https://tsplay.dev/mMM8Vm

我得到了一个 T 的数组,它有 string 类型的键。所以我想遍历数组中的所有条目和 trim 字符串。

错误: Property 'trim' does not exist on type 'T[Extract<keyof T, string>]'

ifAlreadyExists<T>(
    data: Array<T>,
    key: Extract<keyof T, string>,
  ): boolean {

      return (
        data.filter(
          (item) => {
            const v = item[key];

            return v.trim().toLowerCase()
          }
        ).length === 0)
  }

如何告诉 Typescript item[key] 将是字符串类型?

如 kaya3 所述,您的签名将 key 限制为字符串键,而不是具有字符串值的键。要执行后者,您可以引入一个类型变量 Key(可以是任何键类型),并将数组元素限制为具有由 Key 表示的键的字符串值的对象(即 {[K in Key]: string}):

  ifAlreadyExists<Key extends PropertyKey>(
    data: Array<{[K in Key]: string}>,
    key: Key,
  ): boolean {
    ..
  }

TypeScript playground

忽略过滤器中的布尔值与字符串 return 值,故意 不将 T 限制为 Record<PropertyKey, string>.

使用 type-guard:

  return (
    data.filter(
      (item) => {
        const v = item[key];
        if (typeof v === 'string') {
          return v.trim().toLowerCase();
        }
        return 'something?';
      }
    ).length === 0)

为了加分,您可能只想公开实现有效的密钥。

Only 生成一个类型,其中对于 T 的每个键,其对应的字段可分配给 U.

type Only<T, U> = {
  [K in keyof T]: T[K] extends U ? K : never
}[keyof T];

然后

ifAlreadyExists<T>(
  data: Array<T>,
  key: Only<T, string>, // only keys where values are string-like
): boolean {
  ...
}

而且 Book 形状中还有字符串以外的值。

type Book = {
  id: string;
  title: string;
  isbn: number;
  genre: 'fantasy' | 'horror'
};

const bookList: Array<Book> = [{ id: '222', title: 'Title 1', isbn: 1237681231, genre: 'fantasy' }];
this.ifAlreadyExists(bookList, "id"); // fine
this.ifAlreadyExists(bookList, "title"); // fine
this.ifAlreadyExists(bookList, "genre"); // fine
this.ifAlreadyExists(bookList, "isbn"); // Error! isbn is not string

Playground