在 TypeScript 中创建类似于 Keyof 的自定义 Valueof 来返回属性值类型的联合

David Mbochi Njonge 2023年10月8日
  1. 在 TypeScript 中使用 valueof 返回属性值类型的联合
  2. 在 TypeScript 中使用 keyoftypeof 返回属性值类型的联合
  3. 使用 TypeScript 中的单个键获取属性值类型
  4. 在 TypeScript 中使用泛型在编译时检查键值
在 TypeScript 中创建类似于 Keyof 的自定义 Valueof 来返回属性值类型的联合

在本教程中,我们将学习可以用来返回构成属性或对象的类型的不同方法。

我们可以使用三种方法来实现此功能。其中一种方法利用泛型创建名为 valueof 的自定义类型,该类型返回属性的所有联合类型。

第二种方法使用 keyoftypeof 类型返回属性的所有联合类型。第三种方法根据需要使用单独的键返回单一类型。

我们还将学习在编译时限制键值条目,如果它们不是同一类型,则通过利用泛型和索引访问类型。

在 TypeScript 中使用 valueof 返回属性值类型的联合

转到 Visual Studio Code 并创建一个名为 typescript-types 的文件夹或使用你喜欢的任何名称。在文件夹下创建一个名为 value-types-using-valueof.ts 的文件。

将以下代码复制并粘贴到 value-types-using-valueof.ts 文件中。

type ValueOf<T> = T[keyof T];

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

type ValueOfCustomer = ValueOf<Customer>

let customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
}

function logDetails(customerInfo: ValueOfCustomer){
   console.log(customerInfo)
}

logDetails(customer.firstName)
logDetails(customer.lastName)
logDetails(customer.doB)
logDetails(500)// Error - The union does not include type number

首先,我们定义一个泛型类型 ValueOf<T> 并将其分配给 T[keyof T]T 表示任何类型都可以传递给 ValueOf,无论是属性还是对象。

keyof 返回属于传递类型的所有键类型的联合。

我们创建了包含属性 firstNamelastNamedoBCustomer 对象。前两个属性是字符串类型,最后一个属性是日期类型。

接下来,我们通过将 Customer 传递给 ValueOf<Customer> 泛型类型,创建了一个名为 ValueOfCustomer 的类型。ValueOfCustomer 是我们的新类型,由 Customer 对象中所有关键时间的联合组成。

这意味着 ValueOfCustomer 只能接受类型为字符串和日期的值。

为了验证,我们创建了一个名为 logDetails() 的方法,该方法接受 ValueOfCustomer 类型的参数,并使用它记录 CustomerfirstNamelastNamedoB

请注意,如果我们尝试在方法中传递非字符串或日期类型的值,例如数字,我们将收到错误,因为方法参数只接受字符串或数字。

在 TypeScript 中使用 keyoftypeof 返回属性值类型的联合

在同一文件夹中,创建一个名为 value-types-using-keyof-and-typeof.ts 的文件。将以下代码复制并粘贴到文件中。

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

const customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
} as const

type customertypes = typeof customer[keyof Customer]

function getCustomerInfo(theCustomerTypes: customertypes){
    console.log(theCustomerTypes)
}

getCustomerInfo(customer.firstName)
getCustomerInfo(customer.lastName)
getCustomerInfo(customer.doB)
getCustomerInfo(234)//Error - The union does not include type number

在上面的代码中,我们定义了包含属性 firstNamelastNamedoBCustomer 类型。前两个属性是字符串类型,最后一个属性是日期类型。

Customer 对象使用对象中每个属性的具体值进行初始化。名为 customertypes 的类型已创建并分配给 typeof customer[keyof customer]

在最后一个例子中,我们提到 keyof 返回所有键类型的联合。这已经应用到我们的 Customer 对象上来做同样的事情。

typeof 将返回从 Customer 对象获取的所有类型,这是在 keyof 的帮助下实现的,如代码所示。

为了验证这一点,我们创建了一个名为 getCustomerInfo() 的方法,该方法接受 customertypes 类型的参数,并使用它来记录 Customer 对象的值。

请注意,如果我们尝试传递非字符串或日期类型的值(例如数字),则在该方法中,我们将收到错误消息,因为新类型不包含类型编号。

使用 TypeScript 中的单个键获取属性值类型

在上面的两个示例中,我们已经介绍了如何检索所有值类型的联合,但在某些情况下,你可能只对一种类型的对象感兴趣。

在此示例中,你将学习如何使用单个键检索对象的单个值类型。

在同一文件夹下,创建一个名为 individual-keys.ts 的文件。将以下代码复制并粘贴到文件中。

type Customer = {
    firstName: string,
    lastName: string,
    doB: Date,
}

type date = Customer['doB']

function getDateOfBirth(doB: date): Date{
    return doB;
}

let customer: Customer  ={
    firstName: 'john',
    lastName: 'doe',
    doB: new Date(2022,12,6),
}

getDateOfBirth(customer.doB)
getDateOfBirth(123)//Error - Method accepts a single parameter of type date

在此示例中,我们重用了与前面示例中相同的客户定义。日期类型是通过使用 Customer['doB'] 引用客户定义中的 doB 键创建的。

这意味着新的 date 类型是 Date 类型。getDateOfBirth() 包含一个 date 类型的参数,并已用于验证是否只能将日期类型传递给它,如代码所示。

如果我们尝试传递一个不是 date 类型的值,例如一个数字,我们会得到一个错误,因为参数被限制为单一类型。

在 TypeScript 中使用泛型在编译时检查键值

如前面的示例所示,对象由键和值组成。有时我们可能会面临根据其键更改对象值的要求。

在本教程中,我们将学习确保在编译时检查我们传递的值,以确保它们与键的类型相同。

在同一文件夹下创建一个名为 key-value-checking.ts 的文件。将以下代码复制并粘贴到文件中。

type Shipment = {
    containerItems: string,
    containerSerial: string
    shipmentDate: Date
}

declare function updateShipment<K extends keyof Shipment>(key: K, value: Shipment[K]): void;

updateShipment('containerItems','flowers')
updateShipment('containerSerial','def456');
updateShipment('shipmentDate',new Date(2018,3,14))
updateShipment('shipmentDate',1337)// Error- Shipment object does not contain type number

在上面的代码中,我们定义了一个名为 Shipment 的对象,其中包含参数 containerItemscontainerSerialshipmentDate

前两个属性是字符串类型,最后一个属性是日期类型。我们定义了一个名为 updateShipment() 的通用方法。

updateShipment() 方法接受两个参数,其中一个是键,第二个是 Shipment 对象的值。

键必须是任何类型的 Shipment 对象键,并使用尖括号参数中的 <K extends keyof Shipment> 进行检查。

由于我们有键 K,我们可以通过使用 Shipment[K] 索引 Shipment 对象的键来限制传递给该键的值。使用此定义,我们为键输入的每个值都必须与键的类型相同。

请注意,如果你尝试传递未在 Shipment 对象中定义的值,例如数字,编译器会标记问题。

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub

相关文章 - TypeScript Type