如何在下面的函数‘excludeYoung’中将返回数组中元素的每个‘id’属性标记为只读,并且不修改原始数组?

type Person = {
  id: string;
  name: string;
  age: number;
};
function excludeYoungPersons(person: readonly Person[]): readonly Person[] {
  let data = [...person];
  const result = data.filter(item => item.age > 30)
  return result;
}
export { excludeYoungPersons };

推荐答案

您可以按如下方式修改输出类型(请注意函数签名):

type Person = {
  id: string;
  name: string;
  age: number;
};
function excludeYoungPersons(person: readonly Person[]): ReadonlyArray<Readonly<Person>> {
  let data = [...person];
  const result = data.filter(item => item.age > 30)
  return result;
}

const input: Person[] = [{
  id: "xyz",
  name: "Mary",
  age: 32
}]

const result = excludeYoungPersons(input);
result[0] = { id: "nmp", name: "John", age: 41 };   //error
result[0].id = "rst";  //error!

也就是说,通过使用ReadonlyArray,您将返回一个将数组限制为任何非 destruct 性数组的接口.然后,对于Readonly<Person>,您将按原样考虑实际类型:

type Person = {
  readonly id: string;
  readonly name: string;
  readonly age: number;
};

请记住,这是编译类型判断.如果你需要更强大的东西,你最好转向一个类,而不是POJO(简单-旧的脚本对象).

编辑:如果您只需要一个字段为只读,您可以这样写:

type TResultPerson =
  Omit<Person, "id"> & {
    readonly id: string;
  }

function excludeYoungPersons(person: readonly Person[]): ReadonlyArray<TResultPerson> {
  // (same as original)
}

下面是它的行为:

const result = excludeYoungPersons(input);
result[0] = { id: "nmp", name: "John", age: 41 };   //error
result[0].id = "rst";  //error!
result[0].name = "George";  //OK

编辑:正如@Darryl Noake在下面的 comments 中指出的那样,如果你需要在许多地方解决问题,还有另一个解决方案可以变得有用.

您可以在代码中的某个位置定义此帮助器:

type SemiReadonly<T, K extends keyof T> = Omit<T, K> & Readonly<Pick<T, K>>;

这基本上完全按照您的要求进行,但方式更加灵活.因此,为了将只读设置为"id"字段:

function excludeYoungPersons(person: readonly Person[]): SemiReadonlyArray<Person, "id"> {
  // (same as original)
}

如果您也希望将只读设置为"name"字段:

function excludeYoungPersons(person: readonly Person[]): SemiReadonlyArray<Person, "id" | "name"> {
  // (same as original)
}

Typescript相关问答推荐

如何表示多层深度的泛型类型数组?

匿名静态类推断组成不正确推断

了解类型规则中的关键字

如何使默认导出与CommonJS兼容

在实现自定义主题后,Angular 不会更新视图

ApexCharts条形图未显示最小值.负值

是否将自动导入样式从`~/目录/文件`改为`@/目录/文件`?

声明文件中的类型继承

复选框Angular 在Ngfor中的其他块中重复

17个Angular 的延迟观察.如何在模板中转义@符号?

打字错误TS2305:模块常量没有导出的成员

Angular NG8001错误.组件只能在一个页面上工作,而不是在她的页面上工作

Cypress-验证别名的存在或将别名中的文本与';if';语句中的字符串进行比较

无法缩小深度嵌套对象props 的范围

有没有一种更好的方法来存储内存中的数据,而不是在类型脚本中使用数组和基于索引的函数?

是否可以将类型参数约束为不具有属性?

类型分布在第一个泛型上,但不分布在第二个泛型上

将函数签名合并到重载中

使用 TypeScript 在 SolidJS 中绘制 D3 力图

可选字段和联合之间有什么区别吗?