在TypeScript void函数中更改传递对象的类型

时间:2019-07-07 21:39:41

标签: typescript

假设我有一个函数changeType,它接受​​一个Foo并将其转换为一个Bar

interface Foo {
    num: number;
}

interface Bar {
    str: string;
}

function changeType(foo: Foo): void {
    (foo as any).str = foo.num.toString();
    delete (foo as any).num;
}

let foobar: Foo | Bar = { num: 1 };
changeType(foobar);

是否可以告诉TypeScript编译器运行changeType一定会将传入的参数更改为其他类型?我以为可能会是这样的:

function changeType(foo: Foo): foo as Bar { /*...*/ }

,然后该函数将必须返回foo而不是不返回任何内容。甚至更好的是一些奇怪的语法,例如function(...): void, foo => Bar { ... }

我知道这是一个非常奇怪的情况,但这是处理Object.freeze的一部分-在讨论如何实现时似乎被忽略了。通常,the conversation专注于返回的值,而不关注修改后的传递值本身。

另一种情况是关于继承的。假设您有一个Triangle和一个Parallelogram都继承自Shape

type Point = [number, number];

interface Shape {
    name: 'triangle' | 'square';
    points: Point[];
}

interface Triangle extends Shape {
    name: 'triangle';
    points: [Point, Point, Point];
}

interface Parallelogram extends Shape {
    name: 'parallelogram';
    points: [Point, Point, Point, Point];
}

现在,您想将Triangle 变成一个Parallelogram,而不是创建一个新的Shape对象。

function makeParallelogram(triangle: Triangle): void;
function makeParallelogram(shape: Shape): void {
    Object.assign(shape, {
        name: 'parallelogram',
        points: (shape as Triangle).points.push(calcFourthPoint(shape as Triangle);
    });
}

function calcFourthPoint(triangle: Triangle): Point {
    /* some geometry here */
}

1 个答案:

答案 0 :(得分:2)

使用TypeScript不可能实现您真正想要的。来自GitHub的issue非常接近您想要的。 TypeScript无法深入分析代码的控制流,因此很难从函数的作用中推断出正确的类型。

但是,如果使用return语句,重载和type guards,则可以获得相同的效果。

function isFoo(f: Foo | Bar): f is Foo {
    return (f as Foo).num !== undefined;
}

function changeType(foo: Foo): Bar
function changeType(foo: Bar): Foo
function changeType(foo: Foo | Bar): Foo | Bar {
    if (isFoo(foo)) {
        // Convertion logic can be anything. But I suggest not to mutate original object but create new one and fill it with props.
        let res: Bar = { str: foo.num.toString() }
        return res;
    }
    else {
        let res: Foo = { num: +foo.str }
        return res;
    }
}

以及用法

let foobar: Foo | Bar = { num: 1 };   // Type is Foo
let r: Bar = changeType(foobar);      // Return is Bar