TypeScript未正确检查对象属性

TypeScript未正确检查对象属性,typescript,Typescript,我有一个对象,它有字符串和数字属性值。当我想设置某些字段类型的值时,当使用indexOf方法进行检查时,脚本在检查属性类型时失败 下面是一个例子: type TSomeObject = { title: string, description: string, count: number } const someFunction = (myObj: TSomeObject, field: keyof TSomeObject, newValue: string): TSomeObje

我有一个对象,它有字符串和数字属性值。当我想设置某些字段类型的值时,当使用
indexOf
方法进行检查时,脚本在检查属性类型时失败

下面是一个例子:

type TSomeObject = {
  title: string,
  description: string,
  count: number
}

const someFunction = (myObj: TSomeObject, field: keyof TSomeObject, newValue: string): TSomeObject => {
  if (field === 'title' || field === 'description') {
    myObj[field] = newValue
  }
  return myObj
}

const otherFunction = (myObj: TSomeObject, field: keyof TSomeObject, newValue: string): TSomeObject =>{
  const editableFields = ['title', 'description']
  if (editableFields.indexOf(field) >= 0) {
    // TypeScript error here
    myObj[field] = newValue
  }
  return myObj
}
请参见中的示例

someFunction
工作正常时,
otherFunction
失败并出现TypeScript错误:

类型“string”不可分配给类型“never”


我知道它与类型为
number
count
属性相关,但我检查了要编辑的字段。我做错了什么?

这里发生了一些事情


一种是,
editableFields
被推断为
string[]
,这对于您的目的来说太宽了。自TS3.4以来,您可以使用a来推断更窄的文字类型:

const editableFields = ['title', 'description'] as const;
// const editableFields: readonly ["title", "description"]
现在,
editableFields
是一个元组,其成员已知为
“title”
“description”


接下来,TypeScript不会将
arr.indexOf(x)>=0的结果作为
x
类型的a。因此,即使测试为
true
x
的类型也不会自动缩小为
typeofarr[number]
。这只是TypeScript的一个限制;并非所有可能的测试方法都能被编译器检测到。幸运的是,TypeScript使您能够。在这种情况下,您可能希望制作如下内容:

declare function arrayContains<T extends U, U>(
  haystack: ReadonlyArray<T>, 
  needle: U
): needle is T;
function arrayContains<T extends U, U>(haystack: ReadonlyArray<T>, needle: U): needle is T {
    const widenedHaystack: ReadonlyArray<U> = haystack;
    return widenedHaystack.indexOf(needle) >= 0; 
}
因此,让我们实现
arrayContains()


下一件事是:这是:

幸运的是,您可以安全地将
ReadonlyArray
扩展为
ReadonlyArray
,因此您可以这样编写:

declare function arrayContains<T extends U, U>(
  haystack: ReadonlyArray<T>, 
  needle: U
): needle is T;
function arrayContains<T extends U, U>(haystack: ReadonlyArray<T>, needle: U): needle is T {
    const widenedHaystack: ReadonlyArray<U> = haystack;
    return widenedHaystack.indexOf(needle) >= 0; 
}
函数数组内容(haystack:ReadonlyArray,指针:U):指针是T{
康斯特加宽干草堆:ReadonlyArray=干草堆;
返回加宽草垛。索引(针)>=0;
}
这就行了!相反,您也可以只使用a使编译器静音,如中所示:

function arrayContains<T extends U, U>(haystack: ReadonlyArray<T>, needle: U): needle is T {
    return haystack.indexOf(needle as T) >= 0; // assert
}
函数数组内容(haystack:ReadonlyArray,指针:U):指针是T{
返回haystack.indexOf(针作为T)>=0;//断言
}
但我通常会尽量避免断言,除非它们是必要的,而在这里它们不是。这取决于你


所以,让我们把这一切放在一起:

function arrayContains<T extends U, U>(haystack: ReadonlyArray<T>, needle: U): needle is T {
    const widenedHaystack: ReadonlyArray<U> = haystack;
    return widenedHaystack.indexOf(needle) >= 0; 
}

function otherFunction(myObj: TSomeObject, field: keyof TSomeObject, newValue: string): TSomeObject {
    const editableFields = ['title', 'description'] as const;
    if (arrayContains(editableFields, field)) {
        myObj[field] = newValue
    }
    return myObj
}
函数数组内容(haystack:ReadonlyArray,指针:U):指针是T{
康斯特加宽干草堆:ReadonlyArray=干草堆;
返回加宽草垛。索引(针)>=0;
}
函数otherFunction(myObj:TSomeObject,字段:keyof TSomeObject,newValue:string):TSomeObject{
常量editableFields=['title','description']作为常量;
if(数组内容(可编辑字段,字段)){
myObj[field]=新值
}
返回myObj
}
好的,希望能有帮助。祝你好运


可编辑字段的类型为字符串[]。我试图设置正确的类型,例如:const editableFields:Array=['title','description'],但这只会导致indexOf不起作用work@jcalz操场链接现在已修复。回答得很好!谢谢
function arrayContains<T extends U, U>(haystack: ReadonlyArray<T>, needle: U): needle is T {
    const widenedHaystack: ReadonlyArray<U> = haystack;
    return widenedHaystack.indexOf(needle) >= 0; 
}

function otherFunction(myObj: TSomeObject, field: keyof TSomeObject, newValue: string): TSomeObject {
    const editableFields = ['title', 'description'] as const;
    if (arrayContains(editableFields, field)) {
        myObj[field] = newValue
    }
    return myObj
}