【问题标题】:Typescript: Why doesn't my code compile if a property value comes from a nested object?Typescript:如果属性值来自嵌套对象,为什么我的代码无法编译?
【发布时间】:2021-05-13 13:30:38
【问题描述】:

我为这个糟糕的标题道歉,但我没有更好的词汇来形容它。让我给你看我的代码:

type Foo = "bar" | "baz";

type Consistency  = {
    [K in Foo]: {
        foo: K;
        fooTemplate: `${K} in a template`;
    }
}[Foo]

// I want this to compile (and it does)
const valid1: Consistency = {
    foo: "bar",
    fooTemplate: "bar in a template",
}

const valid2: Consistency = {
    foo: "baz",
    fooTemplate: "baz in a template",
}

export const anFoo: Foo = "bar"

const valid3: Consistency = {
    foo: anFoo,
    fooTemplate: `${anFoo} in a template` as const
}

export interface MyObj {
  temporary: {    
    myProperty: Foo;    
  };
}
const state: MyObj = {
    temporary: {
        myProperty: "bar" 
    }
}
const i: Foo = state.temporary.myProperty;
const valid4: Consistency = { // Why doesn't this one compile????
    foo: i,
    fooTemplate: `${i} in a template` as const
}

// I don't want this to compile (and it doesn't)
const invalid1: Consistency = {
    foo: "bar",
    fooTemplate: "baz in a template",
}

const invalid2: Consistency = {
    foo: "baz",
    fooTemplate: "bar in a template",
}

You can play with this here. 这一切都按照我期望valid4 接受的方式工作。出于某种原因,valid4 无法编译,我想要它。为什么不编译,如何编译?


答案没有明确说明,所以我会:这个问题没有解决方案。

【问题讨论】:

  • 我之前看到过这个错误,工会不能分配给自己,因为工会不能分配给任何一个成员。我敢打赌@jcalz 会比我更好地解释它。你有i,作为作者的你知道这两个地方都是一样的i,但TS 只是将i 视为Foo 类型。如果一个Foo"bar" 而另一个Foo"baz",则可以在两个地方都有一个Foo 类型并且不能分配给Consistency。所以Foo 类型不能保证可分配性。
  • 这与嵌套对象无关,只是anFoo 被键入为"bar" 而不是Foodeclare const anFoo: Foo 也不起作用。

标签: typescript types typescript-typings


【解决方案1】:

我相信答案是这样的,但也许 Jcalz 可以纠正我。

“A”的并集 | “B”实际上有 3 个可分配性。

“A”是可分配的。 “B”是可分配的。 和“A” | “B”是可分配的

这是破坏有效的第三种情况。 在价值层面,这是不可能的,但在类型层面,它的两个“条形”| 都有可能。 “baz”,因此它认为...

{foo: "baz", fooTemplate: "bar as template"}

是可能的。

至于 valid3,这是因为 Typescript 编译器可以检测到你已经硬编码了那里的值,因此即使你断言“Foo”它认为的实际类型是“bar”

【讨论】:

  • 这在我看来是对的……编译器主要不关心变量本身,而是关心变量的类型。没有好办法让编译器自动跟踪两个联合类型值之间的相关性。您必须将编译器拖过单独的案例,例如 i === "bar" ? { foo: i, fooTemplate: `${i} in a template` as const } : { foo: i, fooTemplate: `${i} in a template` as const },它看起来像 this problem 的另一个实例。
  • @jcalz 因为链接到一个未解决的问题,这是否意味着没有解决方案?
  • 没有完美的解决方案,不。当然,有一些解决方法:要么使用像上面的三元这样的冗余代码并获得类型安全,要么使用像{ foo: i, fooTemplate: `${i} in a template` as const } as Consistency; 这样的类型断言并获得便利。据我所知,你不能两者兼得。
猜你喜欢
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 2013-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
相关资源
最近更新 更多