TS2322:类型 '{ [x:字符串]:字符串;}' 不可分配给类型“Record”。打字稿通用

Yur*_*yuk 5 typescript typescript-generics

我对打字稿通用有疑问

代码:

type ValidationError<S> = Record<keyof S, string>;

function validateType<S>(
  key: keyof S,
  value: string,
  type: FieldType | FieldType[],
  errors: ValidationError<S>[],
): void {
  switch (type) {
    case 'email': {
      if (!validator.isEmail(value)) {
        const error: ValidationError<S> = {
          [key]: 'error!',
        };

        errors.push(error);
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但我有打字稿错误“TS2322:类型 '{ [x: string]: string; }' 不可分配给类型 'Record '。” 关于:

const error: ValidationError<S> = {
  [key]: 'error!',
};
Run Code Online (Sandbox Code Playgroud)

有人可以描述为什么会发生错误以及如何修复它吗?

小智 4

这是一个棘手的问题。这就是我怀疑正在发生的事情。当您使用括号符号创建带有动态键的对象时,我认为打字稿会自动假定该动态值的类型为string。所以当你这样做时:

const error = {[key]: "something"} /// type => {[x: string]: string};
Run Code Online (Sandbox Code Playgroud)

而不是写类似的东西

const error = {something: "something"} /// type => {something: string} for example
Run Code Online (Sandbox Code Playgroud)

我找到了两个可以尝试的解决方法,这是第一个:

const error = {
      [key]: "error!"
} as ValidationError<S>
Run Code Online (Sandbox Code Playgroud)

这将使错误消失,但您在这里进行类型转换,因此您断言这是正确的类型。Typescript 会读取此内容并信任您。

第二个解决方法

const error: ValidationError<S> = Object.create({[key]: "error!"})
Run Code Online (Sandbox Code Playgroud)

在这里,您不再强制转换which是一个优点,但您必须使用Object.createwhich不如使用文字那么好。我认为这样做的原因是因为当使用 Object.create 和动态字段创建对象时,打字稿不会将其评估为 type {[x: string]: string}

为了使第二个解决方案更好一点,您可以编写一个辅助函数,例如:

function createValidationError<S>(key: keyof S): ValidationError<S> {
    return Object.create({[key]: "error!"});
}
Run Code Online (Sandbox Code Playgroud)

然后你可以直接调用它,而不是在其他函数中构建对象。

  • Object.create 返回类型是 `any`,tsc 会很乐意编译以下内容: ```const a: { [k in Key]: T[Key] } = Object.create({ random: 100,properties: 200 }) ;```` (2认同)