【问题标题】:Type 'string | boolean' is not assignable to type 'never'. Type 'string' is not assignable to type 'never'键入'字符串 | boolean' 不能分配给类型 'never'。类型“字符串”不可分配给类型“从不”
【发布时间】:2022-05-11 17:03:32
【问题描述】:
interface modal {
    name: string;
    check: boolean;
}

type Key = "name" | "check";

const obj: modal = fn();

function fn():any {
    return {
        name: "hello"
    }
}

class Modal {
    name: string;
    check: boolean;
    constructor() {
        this.name = "";
        this.check = false;
        Object.keys(obj).forEach((key: string) => {
            this[key as keyof modal] = obj[key as keyof modal];
        })
    }
}

我在这个[key as keyof modal] 遇到错误

错误信息:输入'string | boolean' 不能分配给类型 'never'。类型“字符串”不可分配给类型“从不”。

【问题讨论】:

  • Modal 类中,keyof modal 不允许您对Modal 对象进行索引,即使它碰巧与modal 具有相同的键,这是一个不相关的接口。你需要keyof Modal
  • 你的意思是改成this[key as keyof Modal]而不是this[key as keyof modal]?不幸的是,它也不起作用

标签: typescript


【解决方案1】:

Object.keys 总是返回 string[],无论如何。当然,在这种情况下,预计它会返回Array<keyof typeof obj>,但事实并非如此。 请在 github 上查看this list of issues

在这种情况下应该做的第一件事是type assertion

(Object.keys(obj) as Array<keyof typeof obj>)

然而,这还不是结束。 这里还是有错误:

this[key] = obj[key]; // error

一般来说,TS 不喜欢突变。请看my articlethis的回答。

this[key]obj[key] 的类型是 string | boolean

请看这段代码:

type Key = "name" | "check";

let _name: Key = 'name'
let _check: Key = 'check'
obj[_name] = obj[_check] // error

上面的代码几乎和你的一样,除了你的变异在迭代器里面而我的不是。迭代索引和key的类型之间没有绑定。

查看示例:

(Object.keys(obj) as Array<keyof typeof obj>)
  .forEach((key, index) => {
    if (index === 0) {
      const test = key // keyof modal and not "name"
    }
  })

这是正确的行为,因为即使 JS 规范也不能保证第一个 keyname。 JS 引擎保留按任何顺序归还您密钥的权利。当然,在 99.99% 的情况下,您会得到预期的订单,但这并不意味着您有保证。

那么,为什么我们在错误消息中有never? TypeScript 使预期键(联合)相交,因为获得通用类型更安全。 string &amp; boolean 的交集 - 为您提供 never,这就是您收到此错误消息的原因。


我相信不使用type assertions 的最佳方法就是致电reduce

interface modal {
  name: string;
  check: boolean;
}

type Key = "name" | "check";

const obj: modal = fn();

function fn(): any {
  return {
    name: "hello"
  }
}

class Modal implements modal {
  name: string;
  check: boolean;
  constructor() {
    this.name = "";
    this.check = false;
    const result = (Object.keys(obj) as Array<keyof typeof obj>)
      .reduce((acc, key) => ({
        ...acc,
        [key]: obj[key]
      }), this)
    Object.assign(this, result)
  }
}

Playground 值得使用implements modal或大写modal接口。

【讨论】:

    猜你喜欢
    • 2021-04-06
    • 2021-08-19
    • 2021-06-12
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多