gpt4 book ai didi

TypeScript 条件返回类型 : works for one condition but not for two

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

我有一个基于 discriminated union 创建形状的工厂函数形状参数,例如:

interface CircleArgs { type: "circle", radius: number };
interface SquareArgs { type: "square", length: number };

type ShapeArgs = CircleArgs | SquareArgs;

class Circle { constructor(_: CircleArgs) {}}
class Square { constructor(_: SquareArgs) {}}

type Shape = Circle | Square;

type ShapeOfArgs<Args extends ShapeArgs> =
Args extends CircleArgs? Circle :
Square;

function createShape<Args extends ShapeArgs>(args: Args): ShapeOfArgs<Args> {
switch (args.type) {
case "circle": return new Circle(args);
case "square": return new Square(args);
}
}

这样做不仅有助于 TS 从参数中推断出正确的返回类型:

const circle1 = createShape({type: "circle", radius: 1}); // inferred as Circle
const square1 = createShape({type: "square", length: 1}); // inferred as Square

但如果我需要将调用包装在另一个函数中,也会正确传播返回类型:

class Container { insert(_: Shape): void {}; }

function createShapeIn<Args extends ShapeArgs>(args: Args, cont: Container) {
const shape = createShape(args);
cont.insert(shape);

return shape;
}

const cont = new Container();
const circle2 = createShapeIn({type: "circle", radius: 1}, cont); // still inferred as Circle
const square2 = createShapeIn({type: "square", length: 1}, cont); // still inferred as Square

然而...

如果我再添加一种类型,一切都会崩溃。

让我们添加另一种类型的形状,称为 Figure:

interface FigureArgs { type: "figure", amount: number };
class Figure { constructor(_: FigureArgs) {}}

那么我们的联合类型将是:

type ShapeArgs = CircleArgs | SquareArgs | FigureArgs;
type Shape = Circle | Square | Figure;

最后,条件类型改为:

type ShapeOfArgs<Args extends ShapeArgs> = 
Args extends CircleArgs? Circle :
Args extends SquareArgs? Square :
Figure;

现在这不再转译:

function createShape<Args extends ShapeArgs>(args: Args): ShapeOfArgs<Args> {
switch (args.type) {
case "circle": return new Circle(args); // error: Circle not assignable ShapeOfArgs<Args>
case "square": return new Square(args); // error: Square not assignable ShapeOfArgs<Args>
case "figure": return new Figure(args); // error: Figure not assignable ShapeOfArgs<Args>
}
}

我做错了什么?

PS:我知道我可以使用 as 运算符强制它,但这违背了类型检查的目的。

TS Playground 链接:

最佳答案

一个非常简单的解决方案是制作一个“类型字典”,而不是联合和条件类型:

// Dictionary of types
type ShapeByType = {
circle: Circle,
square: Square,
figure: Figure
}

function createShape<Args extends ShapeArgs>(args: Args): ShapeByType[Args["type"]] {
switch (args.type) {
case "circle": return new Circle(args);
case "square": return new Square(args);
case "figure": return new Figure(args);
}
}

const circle1 = createShape({type: "circle", radius: 1});
// ^? Circle

// ...

const circle2 = createShapeIn({type: "circle", radius: 1}, container);
// ^? Circle

有了这个,可以更容易地缩放到任意数量的形状。

Playground Link

关于TypeScript 条件返回类型 : works for one condition but not for two,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74724483/

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