在 TypeScript 中强制执行对象值的类型

使用 Record 实用程序类型强制执行 TypeScript 中对象值的类型,例如 type Animal = Record<string, string>。 Record 实用程序类型构造一个对象类型,其键和值具有特定类型。

// 👇️ function returning an object
// whose keys and values are of type string
function getObj(): Record<string, string> {
  return { name: 'Tom', country: 'Chile' };
}

type Animal = Record<string, string>;

const a1: Animal = { name: 'Alfred', type: 'dog' };

Record 实用程序类型可用于将一种类型的属性映射到另一种类型。

我们传递给泛型的第一个类型是键的类型,第二个是值的类型。

type Animal = Record<string, number>;

const a1: Animal = { age: 3, num: 6 };

如果我们提前知道键的名称,则可以使用 union 来限制它们。

type Animal = Record<'name' | 'type' | 'age', string | number>;

const a1: Animal = { name: 'Alfred', type: 'dog', age: 3 };

如果我们尝试在对象上设置具有不同名称的键,类型检查器将抛出错误。

type Animal = Record<'name' | 'type' | 'age', string | number>;

// ⛔️ Error: Type '{ country: string; type: string; age: number; }'
// is not assignable to type 'Animal'.
const a1: Animal = { country: 'UK', type: 'dog', age: 3 };

下面是一个将对象的键限制为特定字符串的并集并将其值设置为包含 role 和 salary 属性的对象的示例。

interface EmployeeData {
  role: string;
  salary: number;
}

type EmployeeName = 'tom' | 'alice' | 'jeff';

const employees: Record<EmployeeName, EmployeeData> = {
  tom: { role: 'accountant', salary: 10 },
  alice: { role: 'manager', salary: 15 },
  jeff: { role: 'programmer', salary: 17 },
};

尝试添加对象上不存在的键会导致类型检查器抛出错误。

interface EmployeeData {
  role: string;
  salary: number;
}

type EmployeeName = 'tom' | 'alice' | 'jeff';

const employees: Record<EmployeeName, EmployeeData> = {
  tom: { role: 'accountant', salary: 10 },
  alice: { role: 'manager', salary: 15 },
  jeff: { role: 'programmer', salary: 17 },
  // ⛔️ Error: Object literal may only specify known
  // properties, and 'ben' does not exist in type
  // 'Record<EmployeeName, EmployeeData>'.
  ben: { role: 'programmer', salary: 17 },
};

Record 实用程序类型允许我们在键入对象的键和值时尽可能宽泛或狭窄。

如果我们知道某些对象键的名称,但希望能够包含具有其他名称的键(只要它们具有正确类型的值),请使用 union 类型。

interface EmployeeData {
  role: string;
  salary: number;
}

type EmployeeName = 'tom' | 'alice' | 'jeff';

//                        👇️ use Union here
const employees: Record<string | EmployeeName, EmployeeData> = {
  tom: { role: 'accountant', salary: 10 },
  alice: { role: 'manager', salary: 15 },
  jeff: { role: 'programmer', salary: 17 },
  ben: { role: 'programmer', salary: 17 },
};

这使我们能够具体说明我们知道的键的名称,但仍然允许使用其他键,只要它们具有正确类型的值即可。