0

我需要通过字符串属性名称更新类的属性值。我首先通过此方法确保属性名称有效:

export class ClientDTO {
    ...

    static isValidPropertyName(name: string): name is keyof ClientDTO {
        return (name as keyof ClientDTO) !== undefined
    }
}

然后在另一堂课上,我正在这样做:

foo(key: string, newValue: string) {
  if (!ClientDTO.isValidPropertyName(key)) {
    return
  }

  if (newValue !== this.originalClient[key]) {
    // @ts-ignore
    this.originalClient[key] = newValue
  }
}

查找现在运行良好,但要进行更新,我必须把它放在// @ts-ignore那里,我真的很想弄清楚如何正确地做到这一点,而不必在那里忽略。

我打开了严格的检查,所以我得到了错误

TS2322:类型“任何”不可分配给类型“从不”

4

2 回答 2

1

问题是您的自定义类型保护:

isValidPropertyName(name: string): name is keyof ClientDTO { ... }

正在防范 的任何键ClientDTO,因此当您尝试使用它时:

this.originalClient[key] = newValue // newValue is type string

TypeScript 试图推断this.originalClient[key]. 由于key可以是的任何ClientDTO,因此您分配给它的值必须可分配给这些键的所有值类型。由于这些键的值类型混合在一起,因此唯一可以分配给它们的类型是底部类型never;无法为其分配任何内容的类型,因此会出现错误。

要解决此问题,请注意您提供newValuetype string。因此,将您的类型保护限制为只有那些ClientDTO谁的值是字符串的键:

type KeysWithStringValues<T extends {}> = {
    [K in keyof T]: T[K] extends string ? K : never;
}[keyof T];

class ClientDTO {
    /* ... */
    static isValidPropertyName(name: string): name is KeysWithStringValues<ClientDTO> {
        // Make sure to replace this with code that ACTUALLY enforces
        // the above constraint.
        return name !== undefined
    }
}

游乐场链接。

于 2020-05-09T01:14:32.613 回答
1
return (name as keyof ClientDTO) !== undefined

这不会检查这name是 ClientDTO 的键。它断言它是,然后检查字符串是否未定义。在操场上试试。

即使这样有效,它也只会检查该字符串是否是 ClientDTO 的有效键,但不会说明它是哪一个。因此,Typescript 会检查您设置的类型是否可以安全地分配给ClientDTO 的任何键;由于 ClientDTO 包含“混合类型”,包括“字符串、布尔值、日期和数字”,因此分配的唯一安全值是never.

为了安全地分配 a newValue: string,您需要一个函数来确保在运行时您的keyis 用于string-typed 属性,这可能涉及一些重复。

class MyClass {
    constructor(
        public a: string,
        public b: string,
        public c: string,
        public x: number,
        public y: number,
        public z: number) { }
}

function isStringProperty(propertyName: string): propertyName is "a" | "b" | "c" {
    return ["a", "b", "c"].indexOf(propertyName) >= 0;
}

function isNumberProperty(propertyName: string): propertyName is "x" | "y" | "z" {
    return ["x", "y", "z"].indexOf(propertyName) >= 0;
}

function setString(dto: MyClass, key: string, newValue: string) {
    if (isStringProperty(key)) {
        dto[key] = newValue;
    }
}

function setNumber(dto: MyClass, key: string, newValue: number) {
    if (isNumberProperty(key)) {
        dto[key] = newValue;
    }
}

打字稿游乐场

另请参阅:Typescript 错误:Type 'number' is not assignable to type 'never'

于 2020-05-09T01:03:09.290 回答