我有一个名为Carlot的对象,它看起来像这样

interface Car {
  model: string;
  year: number;
}

const carLot: Record<string, Car> = {
  oldCar: {
    model: "acura",
    year: 1998,
  },
  otherCar: {
    model: "Mitsubishi",
    year: 1995,
  }
}

我希望将所有键设置为只读,这样当对象在其他地方被读取时,用户只能访问该对象中存在的属性.我很清楚,如果我执行如下操作,我可以将键分别声明为它们自己的类型

type carKeys = "oldCar" | "otherCar"

// and then do
const carLot: Record<carKeys, Car> {
  ...
}

但是,我预计我的对象将有数百个甚至多达1000个密钥,我不想逐个声明它们.我还希望将类型声明保留在对象本身中.这样一来,用户添加的新车也会进行类型判断.有没有一种干净的方法来声明这个类型?

推荐答案

您希望编译器将carLot的类型设置为infer,以使其具有类型Carreadonly properties的已知键.嘿,甚至可能是Readonly<Car>类型的,使用the Readonly utility type来确保Car的属性本身是readonly.老实说,我不确定你是否真的在乎readonly.

重要的是:不必指定两次键,一次在类型中,一次在对象文字值中,只需将它们写入对象文字中并进行推断即可.

有时您可以使用the satisfies operator来完成此操作,但当我try 使用它时,无论如何都会将属性设置为非readonly.哦,好吧.相反,您可以使用更通用的方法来编写generic帮助器函数,该函数只返回其输入,但指导推理.在本例中,它看起来如下所示:

const asCarLot = <K extends string>(
  r: { readonly [P in K]: Readonly<Car> }
) => r;

现在,你写的是const carLot = asCarLot({⋯}),而不是const carLot: SomeCarLotType = {⋯}.如下所示:

const carLot = asCarLot({
  oldCar: {
    model: "acura",
    year: 1998,
  },
  otherCar: {
    model: "Mitsubishi",
    year: 1995,
  }
});

/* const carLot: {
    readonly oldCar: Readonly<Car>;
    readonly otherCar: Readonly<Car>;
} */

您可以看到,carLot已被推断为所需类型.如果编辑对象文字以添加新条目,则carLot的类型将相应更改:

const carLot = asCarLot({
  oldCar: {
    model: "acura",
    year: 1998,
  },
  otherCar: {
    model: "Mitsubishi",
    year: 1995,
  },
  yetAnother: {
    model: "Yugo", 
    year: 1994
  }
});

/* const carLot: {
    readonly oldCar: Readonly<Car>;
    readonly otherCar: Readonly<Car>;
    readonly yetAnother: Readonly<Car>;
} */

如果您编辑对象文字以将值设置为非Car兼容类型,它将相应地发出错误:

const carLot = asCarLot({
  oldCar: {
    model: "acura",
    year: "nineteen ninety eight", // error
  },
  otherCar: {
    model: "Mitsubishi",
    year: 1995,
    color: "blue", // error
  }
});

Playground link to code

Typescript相关问答推荐

类型断言添加到类型而不是替换

如何用不同的键值初始化角react 形式

使某些类型的字段变为可选字段'

在配置对象上映射时,类型脚本不正确地推断函数参数

React typescribe Jest调用函数

如何为父类构造函数中的修饰属性赋值?

根据另一个属性的值来推断属性的类型

如何创建一家Reduxstore ?

在排版修饰器中推断方法响应类型

找不到财产的标准方式?

是否可以强制静态方法将同一类型的对象返回其自己的类?

如何使这种一对一关系在旧表上起作用?

如何从对象或类动态生成类型

使用ngfor循环时,数据未绑定到表

TypeScrip:如何缩小具有联合类型属性的对象

从以下内容之一提取属性类型

Next 13 + React 18 createContext 类型的构建问题

Typescript 和 Rust 中跨平台的位移数字不一致

基于参数的 TS 返回类型

递归地排除/省略两种类型之间的公共属性