首页 > 解决方案 > TypeScript:为什么我不能分配类型为 { a: "a", b: "b" } 的对象的有效字段

问题描述

我从一个常量数组创建了以下类型<const>['a', 'b]

const paths = <const>['a', 'b']

type Path = typeof paths[number]

type PathMap = {
  [path in Path]: path
}

Path等于"a" | "b"

PathMap等于{a: "a", b: "b"}

然后下面的代码编译得很好:

const BASE_PATHS = paths.reduce((map: PathMap, p: Path) => {
  map['a'] = 'a'
  return map
}, <PathMap>{})

这也有效:

const BASE_PATHS = paths.reduce((map: PathMap, p: Path) => {
  return { ...map, [p]: p }
}, <PathMap>{})

但以下代码无法编译:

const BASE_PATHS = paths.reduce((map: PathMap, p: Path) => {
  map[p] = p
  return map
}, <PathMap>{})

这给了我这个错误map[p] = p

TS2322: Type 'string' is not assignable to type 'never'.   Type 'string' is not assignable to type 'never'.

为什么会这样?

感谢您的帮助!

标签: typescripttypescript-generics

解决方案


我相信这是因为对象的键类型是逆变的。

有关更多信息,请参阅答案。

同样,同一类型变量在逆变位置的多个候选会导致推断出交集类型。

const paths = ['a', 'b'] as const

type Path = typeof paths[number]

type PathMap = {
    [path in Path]: path
}

type a = 'a'
type b = 'b'

type c = a & b // never

{
    const BASE_PATHS = paths.reduce((map: PathMap, p: Path) => {
        let x = map[p]
        map[p] = p // same here
        return map
    }, {} as PathMap)

的交集ab产生never

如果as const从中删除paths将编译,因为string & string = string

顺便说一句,由于您使用的是功能方法,请尽量避免对象突变。

在这里,在我的博客中,您可以找到有关 TS 突变的更多信息

归功于@aleksxor

在这里你可以找到官方解释


推荐阅读