【问题标题】:How to Omit a property from a type?如何从类型中省略属性?
【发布时间】:2019-09-06 07:32:50
【问题描述】:

我对 Typescript 中的 Omit 类型有疑问,所以我知道 Omit 类型与 Pick 是相反的,并且是这样构建的:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

但我不知道如何构造 Omit 类型。我有一个Student 的界面,看起来像这样:

interface Student { 
name: string, 
surname: string, 
age: number, 
email: string 
}

我需要一个函数,该函数将具有某些给定属性的学生作为输入并输出省略的学生。该函数应如下所示:

let omit_student = <K extends keyof Student>(student: Student, ...props: K[] ): Omit<Student, K> => null!

但我不知道如何动态地省略 Student 中的给定属性以及函数体中应该发生什么。

这样调用函数:omit_student(student1, "name", "age") 应该输出以下类型:

{ 
surname: string, 
email: string 
}

【问题讨论】:

  • 到目前为止你有什么尝试?

标签: typescript types


【解决方案1】:

要声明Omit 类型,请使用CRice 的答案:

interface Student { 
    name: string, 
    surname: string, 
    age: number, 
    email: string 
}

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

let student: Student = { name: "John", surname: "Doe", age: 21, email: "John.Doe@test.com" }
let omit_student: Omit<Student, "name" | "age"> = student

这将创建一个只有surnameemail 的新类型。然而,这只会在编译时抱怨(当使用除surnameemail 之外的其他属性时),您必须自己编写一个过滤器方法以符合您使用Omit 描述的接口

function omitStudent(student: Student, ...args: string[]): Omit<Student, "name" | "age"> {
    for (let key of args) {
        delete student[key]
    }
    return student
}

console.log(student);
console.log(omitStudent(student, "name", "age"));

虽然我意识到这可能不像您在问题中所问的那样“动态”。

【讨论】:

  • 这个问题是它不会做任何事情,你只是将学生分配给 omit_student。当您console.log(omit_student) 时,它会打印原始学生以及所有属性
【解决方案2】:

TypeScript 中的对象类型不是exact,这是一个常见的混淆来源。 Student 类型的值已知具有适当类型的 namesurnameageemail 属性,但不知道它具有 只有这些属性。这允许您通过向它们添加已知属性来extend 类型:

interface Student { 
    name: string, 
    surname: string, 
    age: number, 
    email: string 
}

interface HogwartsStudent extends Student {
    house: string,
    spells: string[]
}

在上面,HogwartsStudentStudent 的特殊类型。如果我给你一个Student,你不知道她不是一个HogwartsStudent,所以你不能确定她没有housespells 属性。

Omit&lt;T, K&gt; 类型别名产生T超类型。也就是说,T 扩展了 Omit&lt;T, K&gt;。每个T 类型的值也是Omit&lt;T, K&gt; 类型的值。您在Omit&lt;T, K&gt; 中“省略”的只是已知的属性的存在和类型以及K 中的键。


您要求的不仅是从类型中删除已知键,而且是从生成的对象中删除实际属性。这需要在运行时以与 JavaScript 完全相同的方式发生:

function omit_student<K extends Array<keyof Student>>(
  student: Student, ...props: K): Omit<Student, K[number]> {
    const newStudent: Omit<Student, K[number]> = Object.assign({}, student);
    for (let prop of props) {
        delete (newStudent as any)[prop];
    }
    return newStudent;
}

请注意,我已将 rest tuple type 用于 K 参数,但您也可以按照自己的方式进行操作。

希望对您有所帮助。祝你好运!

【讨论】:

  • 我去看看
猜你喜欢
  • 2021-09-16
  • 1970-01-01
  • 2021-07-06
  • 2020-09-21
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
  • 1970-01-01
相关资源
最近更新 更多