gpt4 book ai didi

带有一般错误的 typescript 缩小类型

转载 作者:行者123 更新时间:2023-12-04 03:26:42 26 4
gpt4 key购买 nike

谁能帮我理解这里发生了什么:TS playground

基本上我有一个 store 有一个 exec 方法,我想为子进程缩小 exec 参数的类型但是好像有错误,store类型是泛型

type Param<Options> = {
[K in keyof Options]: Readonly<{
id: K,
options: Options[K],
}>
}[keyof Options];

interface Store<Options> {
exec: (nextState: Param<Options>) => void
}

type ParentOptions = {
'a': { a: string },
} & SubOptions

type SubOptions = {
'b': { b: number },
}

function test(
parentFlowExec: (nextState: Param<ParentOptions>) => void,
subFlowExec: (nextState: Param<SubOptions>) => void,

parentNonGeneric: { exec: (nextState: Param<ParentOptions>) => void },
subNonGeneric: { exec: (nextState: Param<SubOptions>) => void },

parentFlow: Store<ParentOptions>,
subFlow: Store<SubOptions>,

) {
parentFlowExec = subFlowExec; // error: ok
subFlowExec = parentFlowExec; // passed

parentNonGeneric = subNonGeneric; // error: ok
subNonGeneric = parentNonGeneric; // passed

parentFlow = subFlow; // error: ok
subFlow = parentFlow; // error ??

// I plan to use it like this
subProcess(parentFlow);
}

function subProcess(flowStore: Store<SubOptions>) {
flowStore.exec({ id: 'a', options: { a: 'a' } }); // can't call with 'a'
flowStore.exec({ id: 'b', options: { b: 3 } }); // ok
}

更新:我将参数移出并得到 it working但仍然不明白为什么嵌套它们不起作用

interface Store<Options> {
exec: (nextState: Options) => void
}
// parent2: Store2<Param<ParentOptions>>,
// sub2: Store2<Param<SubOptions>>,

最佳答案

为了回答您的问题,首先,让我们快速回顾一下不同“方差”的含义。在下表中,我使用了 Microsoft 的 .NET documentation 中的定义。 (文档中没有的双方差除外)因为我发现它们最容易掌握:

<表类="s-表"><头>方差含义允许替换<正文>双方差同时协变和逆变父类(super class)型 -> 子类型,子类型 -> 父类(super class)型协方差使您能够使用比最初指定的更派生的类型父类(super class)型 -> 子类型逆变使您能够使用比最初指定的派生类型更少的类型子类型 -> 父类(super class)型不变性表示只能使用原来指定的类型无

让我们检查一下您的类型中哪些是父类(super class)型,哪些是子类型:

type T1 = SubOptions extends ParentOptions ? true : false; // false
type T2 = ParentOptions extends SubOptions ? true : false; // true

接下来是 PartentOptionsSubOptions 的子类型,而后者是它的父类(super class)型。它告诉我们什么?它告诉我们,当你注释 subFlow作为Store<SubOptions>然后尝试分配 parentFlow对于它(注释为 Store<ParentOptions>),您正在尝试分配一个 子类型,其中需要一个父类(super class)型

如果我们引用方差表,我们会看到这需要协方差,但是当您收到错误时,这意味着我们正在处理逆变 或 < em>不变性。现在,当您分配 subFlowparentFlow ,您正在分配一个需要子类型的父类(super class)型

上面也会导致错误,意味着这里的赋值实际上是不变,并且@captain-yossariancomment是正确的:

I believe that it is because subFlow and parentFlow are invariant to each other.

然而,这种行为是 TypeScript 的设计限制(参见 Anders Hejlsberg 的 comment 相关问题)牺牲了一些灵 active 以保证稳健性(删除 [keyof Options] 索引,您将看到逆变赋值成为可能) .

至于您的解决方案,由于方差分析的工作原理,当您移动 Params 时向外,参数类型变为协变(因为 T[keyof T] 在这里没有别名。请注意,当简化为裸结构时, Param 类型正是: type Param<Options> = Options[keyof Options] ,仅映射1).

看一下您的解决方案的简化示例0:

type Param<Options> = {
[K in keyof Options]: Readonly<{
id: K,
options: Options[K],
}>
}[keyof Options];

interface Store<Options> {
exec: (nextState: Options) => void
}

type SuperOptions = { 'b': { b: number } }
type SubOptions = { 'a': { a: string } } & SuperOptions

const test1 = (subtype: Store<Param<SubOptions>>) => subProcess1(subtype); // OK, Subtype -> Supertype, covariance
const test2 = (supertype: Store<Param<SuperOptions>>) => subProcess2(supertype); // error, Supertype -> Subtype, contravariance

const subProcess1 = (supertype: Store<Param<SuperOptions>>) => supertype.exec({ id: 'b', options: { b: 3 } }); // ok
const subProcess2 = (subtype: Store<Param<SubOptions>>) => subtype.exec({ id: 'b', options: { b: 3 } }); // ok

Playground


0 你的命名选择稍微增加了一个已经很棘手的问题的困惑:一个子类型被称为 ParentOptions和父类(super class)型 SubOptions ,而它们之间的关系是相反的,所以我将它们命名为SubOptions。和 SuperOptions相应地使事情更清楚。

1 从评论中的讨论中,必须注意的是 Store<Param<SubOptions>> 之间的关系和 Store<Param<SuperOptions>>在解决方案中是协变T[keyof T]这是逆变(参见 Anders 的 comment - SuperOptions 父类(super class)型的属性少于 SubOptions 子类型,并且没有判别式)。

关于带有一般错误的 typescript 缩小类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67482793/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com