打字稿:如何创建一个新的 key/value 对类型,它的形状与对象数组中的一个对象完全相同?

Typescript: How to create a new key/value pair type that is exactly in the same shape as one of the objects in an array of objects?

我有以下数据:

const pets = [
  {
    type: 'cat',
    name: 'penny'
  },
  {
    type: 'dog',
    name: 'Fido'
  },
  {
    type: 'fish',
    name: 'Nemo'
  }
];

宠物只有在完全符合这 3 种形状(即键和值必须匹配)中的任何一种时才应被视为有效。例如,这是一个有效的宠物:

  {
    type: 'dog',
    name: 'Fido'
  }

这些不是:

  {
    age: 'dog',
    name: 'Fido'
  },

  {
    type: 'dog',
    name: 'Sammy'
  },

等..

我的实际对象比这个大很多,所以我不想手动定义这个类型。如何动态完成?

我试过了,但没有用:

type Pet = {
  [key in keyof typeof pets]: typeof pets[key];
};

您需要在 pets 上使用 an as const assertion 来告诉打字稿推断它可以推断出的最具体的类型。否则 pets 只是键入 { type: string, name: string }[],这没有帮助。

const pets = [
  {
    type: 'cat',
    name: 'penny'
  },
  {
    type: 'dog',
    name: 'Fido'
  },
  {
    type: 'fish',
    name: 'Nemo'
  }
] as const;

现在 pets 输入为:

const pets: readonly [{
    readonly type: "cat";
    readonly name: "penny";
}, {
    readonly type: "dog";
    readonly name: "Fido";
}, {
    readonly type: "fish";
    readonly name: "Nemo";
}]

请注意三个特定对象如何具有不同的特定字符串。

现在 Pet 类型就是:

type Pet = typeof pets[number]
/*
{
    readonly type: "cat";
    readonly name: "penny";
} | {
    readonly type: "dog";
    readonly name: "Fido";
} | {
    readonly type: "fish";
    readonly name: "Nemo";
}
*/

通过 number 索引数组类型得到所有数组成员类型的联合。在这种情况下,每种特定类型的宠物。

现在一切如你所愿:

const fido: Pet = { // works
    type: 'dog',
    name: 'Fido'
}

const bad1: Pet = { // error because Nemo is a fish
    type: 'cat', 
    name: 'Nemo'
}

const bad2: Pet = { // error because penny is a cat
    type: 'dog',
    name: 'penny'
}

See playground

您还可以使用 Recordenum 来固定具有特定值的类型。我不知道这是否正是你想要的,但你可以试试。

// Define the keys here they will make sure that nothing
// other then these keys exist here.
enum Keys {
  TYPE = "type",
  NAME = "name",
}

// Create a Record type that can only take this key but any string value
type Pet = Record<Keys, string>;

const pets: Pet[] = [
  {
    type: "cat",
    name: "penny",
  },
  {
    type: "dog",
    name: "Fido",
  },
  {
    type: "fish",
    name: "Nemo",
  },
];

// Valid
const pet: Pet = {
  type: "cat",
  name: "fido",
};

// Invalid
const invalidPet: Pet = {
    age: 'dog',
    name: 'Fido'
};

再次注意,键定义了您可以将什么作为键,而值不受限制,它们可以是任何东西。

如果您也想限制值(不是有效的情况,因为它没有任何意义),您也可以为此创建一个 enum