我们的代码在TypScript 4.7.4下可以正常编译和运行,但我们现在正在try 从TypScript 4.7.4升级到新版本.我们在4.8.4上编译时看到一个错误,而在4.7.4上编译时则不存在该错误.

我已将该错误隔离到其自己的小代码片段中.使用4.8.4(或任何更新的TypScript版本)进行编译时,我们会遇到这样的错误:

src/example2.ts:19:62 - error TS2345: Argument of type 'object' is not assignable to parameter of type 'Record<string, BasicValue>'.
  Index signature for type 'string' is missing in type '{}'.

19         typeof value === 'object' && areFieldsValid(PFields, value, isValidPField);
                                                                ~~~~~

这听起来类似于TypScript 4.8 - https://devblogs.microsoft.com/typescript/announcing-typescript-4-8/#unconstrained-generics-no-longer-assignable-to发布说明中对重大变更的描述,但并不相同

我们的可复制示例代码看起来像:

export interface PNode { 
    'text'?: string
}

export const PFields = ['text'];

export type DefinedBasicValue = number | boolean | string | Array<BasicValue> | {} | {
    [key: string]: BasicValue
    [key: number]: BasicValue
}

export type BasicValue = undefined | DefinedBasicValue


/**
 * Take any object, value, undefined, or null, and determine if it is a PNode
 */
export const isPNode = (value?: {}): value is PNode =>
        typeof value === 'object' && areFieldsValid(PFields, value, isValidPField)

export function areFieldsValid(fields: string[], value: Record<string, BasicValue>, ...validations: ((field: string, value: BasicValue) => boolean)[]): boolean {
    return true
}

export const isValidPField = (field: string, value: BasicValue): boolean => true

错误与函数调用中的value参数(第19行):areFieldsValid(PFields, value, isValidPField)有关.

请有人帮助我们理解为什么这在TS 4.7中可以,但在新版本中却不行?另外,修复此类错误的"最佳"/"正确"方法是什么?我们希望避免"变通办法".

Playground using v4.7.4 with no error

Playground using v4.8.4 with the error

Playground with the current version (v5.4.5) with the error

推荐答案

VLAZ has explained是v4.8中的更改,但它们显示的字体保护并没有阻止isPNode将基元传递给areFieldsValid,这会让我不舒服.

您说过您想用any的值来调用它,包括基元(这将使它返回false).在我看来,这是any的有效用法,但您也可以使用unknown.在这种情况下使用any并不困扰,因为isPNode是一个类型断言,大概是在非类型化世界和类型化世界之间的某种边界上使用的(否则您就不需要允许基元,因为它总是会为它们返回false),并且您说过您确实希望它允许任何值.但如果您遵循"无显式any"规则或在遵循"无显式any"规则的store 工作,您也可以使用unknown{} |零,它们只需要添加类型断言.

any:

export const isPNode = (value?: any): value is PNode =>
    typeof value === 'object' &&
    !!value &&
    areFieldsValid(PFields, value, isValidPField);

Playground link

注意,我添加了&& !!value来淘汰null,因为typeof null"object").

unknown:

export const isPNode = (value?: unknown): value is PNode =>
    typeof value === 'object' &&
    !!value &&
    areFieldsValid(PFields, value as Record<string, BasicValue>, isValidPField);

Playground link

再次注意&& !!value处理null.我认为您无法避免那里的类型断言,尽管我可能错了.我还在习惯unknown.

{} |零

最后,您还可以使用value?: {} |零,尽管我认为这基本上只是value?: any的另一种编写方式.与unknown解决方案相同的实现也适用于该类型:

export const isPNode = (value?: {} |零): value is PNode =>
    typeof value === 'object' &&
    !!value &&
    areFieldsValid(PFields, value as Record<string, BasicValue>, isValidPField);

Playground link

Typescript相关问答推荐

替换类型脚本类型中的多个特定字符串

创建一个根据布尔参数返回类型的异步函数

如何使用Zod使一个基于其他字段值的字段为必填字段?

使用Dockerfile运行Vite React应用程序时访问env变量

有没有可能产生输出T,它在视觉上省略了T中的一些键?

在列表的指令中使用intersectionObservable隐藏按钮

在打印脚本中使用泛型扩展抽象类

将具有Readonly数组属性的对象接口转换为数组

正确使用相交类型的打字集

为什么Typescript只在调用方提供显式泛型类型参数时推断此函数的返回类型?

类型与泛型抽象类中的类型不可比较

为什么发送空字段?

对于VUE3,错误XX不存在于从不存在的类型上意味着什么?

在REACT查询中获取未定义的isLoading态

仅当类型为联合类型时映射属性类型

如何通过nx找到所有受影响的项目?

覆盖高阶组件中的 prop 时的泛型推理

如何在由函数参数推断的记录类型中具有多个对象字段类型

可选通用映射器函数出错

基于可选参数的动态类型泛型类型