假设我有一个泛型函数,它获取一个类型为keyof T的参数,并使用该参数创建一个Partial对象.

下面的代码生成错误:类型‘{[x:字符串]:NULL;}’不可分配给类型‘Partial’:

const notWorkingPk = <T>(pk: keyof T): Partial<T> => {
    const condition: Partial<T> = {
        [pk]: undefined
    };
};

然而,该代码运行得很好:

const workingPk = <T>(pk: keyof T): void => {
    const condition: Partial<T> = {};

    condition[pk] = undefined;
};

TS Playground

我的问题是,为什么,有没有一种方法可以用第一种方式编写代码?

推荐答案

字体判断器不能真正准确地确定何时可以将特定值分配给generic类型.在泛型上有很少的操作,而TypeScrip可以正确地进行"推理".对于大多数操作,它要么将泛型类型视为opaque,不能将任何不相同的类型视为可赋值类型,要么放弃并将泛型类型参数替换为其constraints.在前一种情况下,这是非常严格的,可能会导致误报(安全代码上的错误),而后一种情况最终会过于宽松,并导致假阴性(不安全代码上的错误失败).


前一种情况是发生在

const condition: Partial<T> = {
    [pk]: undefined
}; // error!

编译器将Partial<T>视为大部分不透明的,并且不接受{[pk]: undefined}作为可能的值,即使对于任何T应该允许undefined作为Partial<T>的任何属性的值(假设您没有启用the --exactOptionalPropertyTypes compiler option).事实上,如果您将T更改为某个特定类型,则赋值将成功.但是编译器不能推论undefined对于一般情况是允许的.这是在microsoft/TypeScript#22229中描述的.如果您希望编译器接受这一点,您应该使用type assertion:

const condition = {
    [pk]: undefined
}  as Partial<T>;

后一种情况发生在

const condition: Partial<T> = {};
condition[pk] = undefined;

对于泛型T,编译器将{}视为可以赋值给Partial<T>的为数不多的有效类型之一(这必须显式实现),然后当您将其赋值给condition[pk]时,编译器就松懈了,允许赋值undefined.这恰好是安全的,但是编译器并没有真正正确地判断它.

这是在第microsoft/TypeScript#30989节中所描述的.类似的情况在这里也发生了:

const compare = <T extends {a: string}>(s: string) => {   
    const p: Partial<T> = {a: s}; // error

    const o: Partial<T> = {};
    o.a = s; // okay
}

The p line gives an error while the o code accepts it, but in this case it is the error that's correct, because maybe T will be specified with a type like {a: "x" | "y"} and calling compare<{a: "x" | "y"}>("z") will end up trying to assign "z" to a place that should be "x" | "y". See Why can't I return a generic 'T' to satisfy a Partial<T>? for more information about that.


这就是正在发生的事情.编译器不能真正对任意泛型操作进行准确的分析,所以它走捷径.如果它抱怨您知道是安全的东西,您可以使用类型断言来禁止它.

Playground link to code

Typescript相关问答推荐

如何将绑定到实例的类方法复制到类型脚本中的普通对象?

在Typescribe中,extends工作,但当指定派生给super时出错""

基于平台的重定向,Angular 为16

如何键入函数以只接受映射到其他一些特定类型的参数类型?

带占位符的模板文字类型何时扩展另一个?

Typescript泛型类型:按其嵌套属性映射记录列表

如何在Reaction路由v6.4加载器和操作中获得Auth0访问令牌?

为什么不能使用$EVENT接收字符串数组?

TS如何不立即将表达式转换为完全不可变?

是否可以判断某个类型是否已合并为内部类型?

为什么我的动画状态在组件实例之间共享?

如何从MAT-FORM-FIELD-MAT-SELECT中移除焦点?

类型判断数组或对象的isEmpty

如何调整项目数组,但允许权重影响顺序

有没有一种方法可以提升对象的泛型级别,而对象的值是泛型函数?

是否使用类型将方法动态添加到类?

如何避免TS2322;类型any不可分配给类型never;使用索引访问时

如何限定索引值必须与相应属性的id字段相同

根据索引将元组拆分为两个块

基于泛型类型的条件类型,具有条目属性判断