我正在编写一个函数,该函数接受一个对象T和一个属性键,该属性键为keyof T,但进一步约束该属性必须扩展其他类型,例如Date.

(我将继续使用日期类型,但它实际上只是一个示例.

我可以使用以下命令派生出一个 Select 这些属性的类型:

type Dates<T> = {
    [P in keyof T as T[P] extends Date | undefined ? P : never]: T[P]
};

但是,我试图编写一个类型正确的函数,该函数作用于这个属性子集,但失败了.

function doSomething<T>(inst: T, key: keyof T) {
    const date = inst[key];
    //    ^ But must be constrained to the `Date | undefined` type.
}

推荐答案

从概念上讲,考虑到你的Dates定义,你可以这样写:

function doSomething<T>(inst: T, key: keyof Dates<T>) {
   const date = inst[key];
   date?.getdate(); // error
}

但不幸的是,TypeScrip不能"看到"inst[key]是可以赋值给Date | undefined的类型,即使Dates的定义暗示了这一点.TypeScrip缺少"可赋值给类型VT的属性"形式的本机操作符.我通常将其称为KeysMatching<T, V>,其中KeysMatching<T, Date | undefined>相当于您的代码的keyof Dates<T>.当然,您可以定义在某些情况下可以工作的您自己的版本,但是当T是泛型时,编译器不能遵循逻辑.在microsoft/TypeScript#48992处有一个开放的特性请求,以本地支持KeysMatching,但目前它不是语言的一部分,您需要解决它.


我能设想的最小解决办法是以这种方式将T转换为constrain,这样TypeScrip就知道T[keyof Dates<T>]Date | undefined的子类型.例如,如下所示:

function doSomething<
   T extends Record<keyof Dates<T>, Date | undefined>,
>(inst: T, key: keyof Dates<T>) {
   const date = inst[key];
   date?.getDate() // okay
}

这正如广告所说的那样奏效.让我们来测试一下:

const v = { a: "abc", b: new Date(), c: undefined, d: 123 };    
doSomething(v, "b"); // okay
doSomething(v, "c"); // okay
doSomething(v, "a"); // error! 
// Argument of type '"a"' is not assignable to parameter of type '"b" | "c"'

看上go 不错!

Playground link to code

Typescript相关问答推荐

如何在另一个if条件中添加if条件

如何修复VueJS中的val类型不能赋给函数

如何在类型脚本中声明对象其键名称不同但类型相同?

使用FormArray在Angular中添加排序

如何使打包和拆包功能通用?

如何在排版中正确键入中间件链和控制器链

打字脚本中泛型和直接类型重新映射的不同行为

类型{}上不存在属性&STORE&A;-MobX&A;REACT&A;TYPE脚本

已解决:如何使用值类型限制泛型键?

一个打字类型可以实现一个接口吗?

Typescript 类型守卫一个类泛型?

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

如何使用angular15取消选中位于其他组件中的复选框

基于闭包类型缩小泛型类型脚本函数的范围

如何处理可能为空的变量...我知道这不是Null?

如何在TypeScript中描述和实现包含特定属性的函数?

必须从注入上下文调用Angular ResolveFn-inject()

如何向我的自定义样式组件声明 custom.d.ts ?

使用本机 Promise 覆盖 WinJS Promise 作为 Chrome 扩展内容脚本?

当并非所有歧视值都已知时,如何缩小受歧视联盟的范围?