我可以在打字稿中检查联合类型的类型吗?

时间:2015-10-27 21:34:36

标签: typescript

是否有办法针对内置于该语言的联合类型对对象执行“instanceof”式查询?

我有一个带有联合类型的类型别名,如下所示:

type MyType = Foo | Bar | Thing;

FooBarThing中的每一个都继承自Base

class Base { /* ... */ }
class Foo extends Base { /* ... */ }
class Bar extends Base { /* ... */ }
class Thing extends Base { /* ... */ }

某些方法会返回Base

function getBase(): Base { /* ... */ return base; }

理想情况下,我想创建另一种方法,可以在调用MyType后返回getBase()

function getMyType(): MyType { 
    var item = getBase();
    if (item instanceof MyType)
        return item;
    else
        return null;
}

如果MyType不是类型别名,则上述代码可以正常工作。但是,由于它是一个类型别名,它似乎不起作用。那么为了重新思考我的问题,这种语言内置了这种语言吗?

显然,我想要的是通过针对每个单独的类检查instanceof查询来实现:

function getMyType(): MyType { 
    var item = getBase();
    if (item instanceof Foo || item instanceof Bar || item instanceof Thing)
        return item;
    else
        return null;
}

但这并不理想;如果某个未来的开发人员想要创建OtherThing并扩展MyType以包含此新类,那么希望记住更新getMyType()

语言中是否有内置功能可以解决此问题,还是有更好的方法可以做到这一点?

2 个答案:

答案 0 :(得分:3)

没有类型别名的运行时表示,所以没有"内置"本身做这种检查本身。

但这种模式可以相当容易维护:

// Future devs: Please keep these in sync
type MyType       =  Foo|Bar|Thing;
let MyTypeClasses = [Foo,Bar,Thing];

function getMyType(): MyType { 
    var item = getBase();
    if (MyTypeClasses.some(c => item instanceof c))
        return item;
    else
        return null;
}

答案 1 :(得分:0)

自从接受的答案发布以来,Typescript引入了一些新功能,使此操作变得更加容易。现在,从Typescript 3.8.3开始,我将在2020年做到这一点:

const myTypes = ['Foo', 'Bar', 'Thing'] as const;
type MyType = typeof myType[number]; // 'Foo' | 'Bar' | 'Thing'

// Return a typed MyType if string is valid (else throw).
function getMyType(maybeMyType: string): MyType {
    const myType = myTypes.find((validType) => validType === maybeMyType);
    if (myType) {
        return myType;
    }
    throw new Error(`String "${maybeMyType}" is not of type MyType.`);
}

// Use it like this:
const definitelyMyType = getMyType('Foo');

或者,如果您更喜欢安全性较低但可读性更高的自定义类型防护样式,则可以这样操作:

// Define a custom type guard to validate & assert that maybeMyType is MyType.
function isMyType(maybeMyType: string): maybeMyType is MyType {
    return maybeMyType in myTypes;
}

// Use it like this:
const maybeMyType = 'Foo';
if (isMyType(maybeMyType)) {
    const definitelyMyType: MyType = maybeMyType;
}