TypeScript 高级类型 - 泛型函数内出现无法访问错误的问题

标签 typescript

我找不到答案为什么通用函数中的 switch 不会在分支内强制转换我的类型。

我的代码是:

interface Id { id: number; }
enum Kind { square = "square", circle = "circle" }
interface Circle { kind: Kind.circle; radius: number; }
interface Square { kind: Kind.square; size: number; }
type Data = Circle | Square;
type ShapeModel<TData> = Id & TData;
class UnreachableError extends Error { public constructor(guard: never) { super(`Unsupported kind: ${JSON.stringify(guard)}`); } }

function myFunctionGeneric<TData extends Data>(data: TData): ShapeModel<TData> {
    switch (data.kind) {
        case Kind.circle:
            return { ...data, id: 1 };
        case Kind.square:
            return { ...data, id: 2 };
        default:
            throw new UnreachableError(data); // <-- UNEXPECTED
        // Argument of type 'TData' is not assignable to parameter of type 'never'.
        // Type 'Data' is not assignable to type 'never'.
        // Type 'Circle' is not assignable to type 'never'.
        // ts(2345)
    }
}

const myCircleData: Circle = { kind: Kind.circle, radius: 42 };
const mySquareData: Square = { kind: Kind.square, size: 42 };

// I want this. I'm passing Circle and want receive ShapeModel<Circle>
const myCircleModel: ShapeModel<Circle> = myFunctionGeneric(myCircleData);

// I want this. I'm passing Square and want receive ShapeModel<Square>
const mySquareModel: ShapeModel<Square> = myFunctionGeneric(mySquareData);

此方法无需通用 TData 即可正常工作。

有人可以解释一下,为什么 TypeScript 无法决定分支中的类型吗?

最佳答案

要缩小类型,它需要是联合,这里没有联合,它是泛型类型参数TData。当然,这扩大了联盟。但 TS 不会试图缩小这一范围。如果你仔细想想,缩小范围是相当困难的,TData 可以是 Circle 的子类型,所以你不能缩小到 Circle在 switch 情况下,它将是某种条件类型。

最简单的解决方案是使用泛型进行公共(public)签名,并使用可以通过 typescript 缩小范围的更简单联合的私有(private)签名。


function myFunctionGeneric<TData extends Data>(data: TData): ShapeModel<TData>
function myFunctionGeneric(data: Data): ShapeModel<Data> {
    switch (data.kind) {
        case Kind.circle:
            return { ...data, id: 1 };
        case Kind.square:
            return { ...data, id: 2 };
        default:
            throw new UnreachableError(data); 
    }
}

Playground Link

关于TypeScript 高级类型 - 泛型函数内出现无法访问错误的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60339173/

相关文章:

angular - 如何使用 Angular 2 中的指令在宿主元素上设置计算宽度

typescript - 如何将 Typescript 函数重载与具有多个参数的函数一起使用?

reactjs - typescript + useRef<X|Y> : Type X is not assignable to type Y

javascript - 针对实际数据库测试 NestJS 服务

typescript - 将私有(private)包安装到 @types - TypeScript 和 NPM

javascript - 创建实例时在构造函数中声明变量而不赋值

angular - 如何使 ngIf 指令在所有项目中全局可见?

angularjs - Visual Studio 2015 Angular2 html 变量智能感知/编译检查

typescript - 根据可选参数指定返回类型

javascript - 使用 Leaflet 和 Angular 6 创建 L.control() 的新实例时出错