简体   繁体   English

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

[英]Change type of passed object in TypeScript void function

Suppose I have a function changeType that takes in a Foo and converts it into a Bar .假设我有一个函数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);

Is there any way to tell the TypeScript compiler that running changeType will necessarily change the passed in argument to a different type?有什么方法可以告诉 TypeScript 编译器运行changeType一定会将传入的参数更改为不同的类型吗? I thought maybe there might be something like:我想也许有这样的事情:

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

and then the function would have to return foo rather than not returning anything.然后该函数必须返回foo而不是不返回任何内容。 Even better would be some strange syntax like function(...): void, foo => Bar { ... } .更好的是一些奇怪的语法,比如function(...): void, foo => Bar { ... }

I know this is a very strange case, but it is part of handling Object.freeze --the part that seems to go ignored when discussing how to implement it.我知道这是一个非常奇怪的情况,但它是处理Object.freeze一部分——在讨论如何实现它时似乎被忽略的部分。 Typically the conversation focuses on the returned value, and not the passed value itself, which is modified.通常,对话侧重于返回值,而不是已修改的传递值本身。

Another case revolves around inheritance.另一个案例与继承有关。 Suppose you have a Triangle and a Parallelogram that both inherit from Shape .假设您有一个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];
}

Now you want to mutate the Triangle into a Parallelogram , rather than creating a new Shape object.现在您想将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 */
}

Exactly what you want is not possible with TypeScript. TypeScript 无法满足您的需求。 This issue from GitHub is very close to what you want.来自 GitHub 的这个issue非常接近你想要的。 TypeScript cannot deeply analyze control flow of your code, so it will have troubles inferring correct types from what function does. TypeScript 无法深入分析代码的控制流,因此很难从函数的功能中推断出正确的类型。

But pretty same effect can be achieved if using return statement, overloading and type guards .但是如果使用 return 语句、重载和类型保护,也可以达到相同的效果。

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;
    }
}

And the usage和用法

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM