我在理解数组上下文中类型脚本中的区别联合时遇到了困难.以documentation中的例子为例,我希望下面的结论完全正确.

interface Circle {
  kind: "circle";
  radius: number;
}
 
interface Square {
  kind: "square";
  sideLength: number;
}
 
type Shape = Circle | Square;

const getShapes = (): Shape[] => {
    const data = [
        { kind: "circle", radius: 1 },
        { kind: "square", sideLength: 3}
    ]
    return data;
}

playground link

我的理解是,这是在说"一个形状必须是圆形或正方形".

相反,它会给出以下错误:

类型‘({种类:字符串;半径:数字;侧长?:未定义;}|{种类:字符串;侧长:数字;半径?:未定义;})[]’不能分配给类型‘Shape[]’. 类型‘{Kind:字符串;RADIUS:Number;side Length?:未定义;}|{Kind:字符串;side Length:Number;RADIUS?:未定义;}’不能赋值给类型‘Shape’. 类型‘{Kind:String;Radius:Numbers;side Length?:Unfined;}’不能赋值给类型‘Shape’. 类型‘{Kind:String;Radius:Numbers;side Length?:Unfined;}’不能赋值给类型‘Square’. 属性"Kind"的类型不兼容. 类型‘字符串’不可赋值给类型‘"Square"".

我特别困惑的是,当kind: string与字面意思匹配时,TypeScrip就是这样解释的.根据我阅读文档的方式,这似乎是一个完美的unions 用法

推荐答案

当呈现不带type annotation的变量声明const data = ⋯时,类型脚本infers基于在广泛的场景中工作良好的启发式推理规则,来自初始化器的变量的类型.它目前没有能力推迟这一过程,并"向前看",看看以后如何使用该变量.vt.给出

const data = [
  { kind: "circle", radius: 1 },
  { kind: "square", sideLength: 3 }
];

编译器会推断出

const data: ({
    kind: string;
    radius: number;
    sideLength?: undefined;
} | {
    kind: string;
    sideLength: number;
    radius?: undefined;
})[]

因为这就是推理规则说要做的.特别是,字符串文字属性被扩展到string,因为人们修改属性值是很常见的.编译器没有看到您打算将data作为Shape[]返回,因此它不知道您打算让kind属性具有字符串literal types.当你遇到return data的时候,已经太晚了.已经设置了data的类型.


如果您想修复这个问题,您应该像const data: Shape[] = ⋯一样注释data,或者您可以在初始化器上使用the satisfies operator来为编译器提供它所缺少的上下文:

const getShapes = (): Shape[] => {
  const data = [
    { kind: "circle", radius: 1 },
    { kind: "square", sideLength: 3 }
  ] satisfies Shape[]
  return data;
}

Playground link to code

Typescript相关问答推荐

在TypScript手册中可以视为接口类型是什么意思?

TypeScript类型不匹配:在返回类型中处理已经声明的Promise Wrapper

类型脚本泛型最初推断然后设置

如何在TypeScrip面向对象程序设计中用方法/属性有条件地扩展类

返回同时具有固定键和变量键的对象的函数的返回类型

迁移到Reaction路由V6时,获取模块Reaction-Router-Dom';没有导出的成员RouteComponentProps错误

如何使用一个字段输入对象,其中每个键只能是数组中对象的id属性,而数组是另一个字段?

如果字符串文字类型是泛型类型,则用反引号将该类型括起来会中断

为什么我的条件类型不能像我预期的那样工作?

是否有一个版本的联合类型递归地使属性只出现在一个可选选项中?

扩展参数必须具有元组类型或传递给REST参数

在HighChats列时间序列图中,十字准线未按预期工作

`fetcher.load`是否等同于Get Submit?

有没有办法在Zod中使用跨字段验证来判断其他字段,然后呈现条件

声明遵循映射类型的接口

带有';的类型脚本嵌套对象可选属性错误满足';

有没有更干净的方法来更新**key of T**的值?

为什么过滤器不改变可能的类型?

如何从联合类型推断函数参数?

Next 13 + React 18 createContext 类型的构建问题